흔히 볼 수 있 는 동적 계획 문제 총화

24835 단어 알고리즘
최근 졸업 할 때 일자 리 를 찾 는 문제 에 직면 해 있다. 각 공장 의 필기시험 문 제 를 풀 때 큰 공장 이 특히 시험 을 보 는 문 제 를 좋아 하 는 것 이 바로 동태 계획 문제 라 는 것 을 발견 했다.그래서 제 가 본 각종 흔히 볼 수 있 는 동적 계획 문 제 를 정리 하고 후기 복습 을 편리 하 게 하기 로 했 습 니 다.동적 기획 은 Dynamic Programming 이 라 고 하 는데 DP 라 고 부른다. 동적 기획 문 제 를 처음 접 할 때 이런 문 제 는 추상 적 이 고 난해 하 며 서로 다른 문제 에 대한 해답 을 구 하 는 사고방식 도 천차만별이다. 그러나 본질 적 으로 보면 동적 기획 문 제 는 가장 핵심 적 인 사상 은 하나의 큰 문 제 를 하나의 하위 문제 로 나 누 는 것 이다.문제 와 하위 문제 간 의 상태 전이 관 계 를 정의 함으로써 문 제 를 점차적으로 해결 할 수 있다.(대부분의 재 귀 문 제 는 동태 적 인 계획 방식 으로 해결 할 수 있 고 시간 복잡 도와 공간 복잡 도 를 크게 줄 일 수 있다)
최 장 증자 시퀀스 (우 객 망 에서 온 것)
하나의 디지털 서열 에 대해 복잡 도 를 O (nlogn) 로 하 는 알고리즘 을 설계 하여 이 서열 의 최 장 상승 서브 서열 의 길 이 를 되 돌려 주 십시오. 여기 의 서브 서열 은 이러한 서열 인 U1, U2 로 정의 합 니 다. 그 중에서 Ui < Ui + 1, 그리고 A [Ui] < A [Ui + 1].디지털 시퀀스 A 와 시퀀스 의 길이 n 을 지정 하고 가장 긴 상승 서브 시퀀스 의 길 이 를 되 돌려 주 십시오.테스트 사례: [2, 1, 4, 3, 1, 5, 6], 7 복귀: 4
여기 서 dp [i] 로 표 지 를 i 로 하 는 요 소 를 증가 서열 의 끝 요소 로 하 는 가장 긴 증가 서브 서열 의 길 이 를 나타 낸다. 여기 서 증가 서열 은 엄격 한 인접 을 요구 하지 않 기 때문에 A [i] 는 모든 A [j] (i > j) 와 비교 해 야 한다. 만약 에 A [i] > A [j] 가 존재 한다 면 i 번 째 요 소 는 j 번 째 요소 뒤에 연결 하여 새로운 증가 서열 의 끝 을 낼 수 있다 는 것 을 의미한다. 따라서 dp [i] = max (dp [j]) + 1;그렇지 않 으 면 i 번 째 요 소 는 앞의 모든 수 보다 작 고 i 요 소 를 마지막 으로 하 는 d 증가 p 시퀀스 의 길 이 는 1 이 므 로 dp [i] = 1 이다.마지막 으로 dp 에서 가장 큰 값 을 꺼 내 면 가장 긴 증가 서브 시퀀스 의 길이 입 니 다.상 태 를 분석 한 후에 문 제 는 쉽게 풀 립 니 다. 여기에 수 동 으로 훑 는 자바 버 전 코드 를 첨부 합 니 다.
public static int[] forward(List list){
        int[] dp = new int[list.size()];
        dp[0] = 1;
//max    j            
        int max;
        for(int i = 1; i < list.size();i++){
            max = 0;
            for(int j = 0; j < i; j++){
                if(list.get(i) > list.get(j)){
                    max = max < dp[j] + 1 ? dp[j] + 1 : max;
                }else{
                    max = max < 1 ? 1 : max;
                }
            }
            dp[i] = max;
        }
        return dp;
    }

최 장 공공 서브 시퀀스 (우 객 망 에서 온 것)
두 문자열 에 대해 효율 적 인 알고리즘 을 설계 하여 그들의 가장 긴 공공 서열 의 길 이 를 구 하 십시오. 이곳 의 가장 긴 공공 서열 은 두 개의 서열 인 U1, U2, U3... Un 과 V1, V2, V3.. Vn 으로 정의 되 는데 그 중에서 Ui & ltUi + 1, Vi & ltvi + 1 이 있 습 니 다.그리고 A [Ui] = B [Vi].두 문자열 A 와 B 를 지정 하고 두 문자열 의 길이 n 과 m 를 지정 합 니 다. 가장 긴 공공 하위 시퀀스 의 길 이 를 되 돌려 주 십시오.두 줄 의 길이 가 모두 300 보다 작 음 을 보증 합 니 다.테스트 샘플: "1A2C3D4B 56", 10, "B1D23CA45B6A", 12 반환: 6
우 리 는 dp [i] [j] 로 A 문자열 의 앞 i 문자 와 B 문자열 의 앞 j 문자 의 가장 긴 공공 서브 시퀀스 길 이 를 표시 합 니 다. 만약 에 A [i] = B [j] 라면 우 리 는 방정식 dp [i] [j] = dp [i - 1] [j - 1] + 1 을 옮 길 수 있 습 니 다. 만약 에 A [i]! =B[j],dp[i][j] = max(dp[i][j-1],dp[i-1][j])。
    public static int findLCS(String A, int n, String B, int m) {
        // write code here
        int[][] dp = new int[n + 1][m + 1];
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                if(A.charAt(i - 1) == B.charAt(j - 1)){
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                }else{
                    dp[i][j] = Math.max(dp[i - 1][j - 1],Math.max(dp[i - 1][j],dp[i][j - 1]));
                }
            }
        }
        return dp[n][m];
    }

최 장 공통 꼬치 (우 객 망 에서 온 것)
두 문자열 에 대해 서 는 시간 복잡 도가 O (m * n) 인 알고리즘 (여기 m 와 n 은 두 문자열 의 길이) 을 설계 하여 두 문자열 의 가장 긴 공공 문자열 의 길 이 를 구 하 십시오.여기 서 가장 긴 공공 하위 문자열 은 두 개의 서열 인 U1, U2,.. Un 과 V1, V2,... Vn 으로 정의 되 는데 그 중에서 Ui + 1 = = Ui + 1, Vi + 1 = = Vi + 1, 동시에 Ui = = Vi.두 문자열 A 와 B 를 지정 하고 두 문자열 의 길이 n 과 m 를 동시에 지정 합 니 다.테스트 샘플: "1AB2345CD", 9, "12345 EF", 7 반환: 4
이 문 제 는 위의 문제 와 유사 하 다. 차이 점 은 여기 가 하위 문자열 이 고 연속 적 인 것 이다. dp [i] [j] 는 A 문자열 의 i - 1 문자 와 B 문자열 의 j - 1 문자 로 끝 나 는 가장 긴 공공 문자열 의 길 이 를 나타 낸다. 그러나 A [i - 1] = B [j - 1] 와 dp [i] [j] = dp [i - 1] [j - 1] [j - 1] + 1;A[i-1] != B [j - 1] 때 그들 로 끝 나 는 공공 문자열 의 길 이 는 반드시 0 이다.마지막 으로 dp 에서 길이 가 가장 큰 값 을 꺼 내 면 가장 긴 공공 문자열 입 니 다.
    public static int findLongest(String A, int n, String B, int m) {
        // write code here
        int[][] dp = new int[n + 1][m + 1];
        int max = 0;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                if(A.charAt(i - 1) == B.charAt(j - 1)){
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                }else{
                    dp[i][j] = 0;
                }
                if(max < dp[i][j]) max = dp[i][j];
            }
        }
        return max;
    }

최소 편집 대가 문제 (우 객 망 중점 내용) 는 두 문자열 A 와 B 에 대해 삽입, 삭제, 수정 작업 을 통 해 A 꼬치 를 B 꼬치 로 바 꾸 고 c0, c1, c2 를 각각 세 가지 작업 의 대가 로 정의 해 야 합 니 다. 효율 적 인 알고리즘 을 설계 하여 A 꼬치 를 B 꼬치 로 바 꾸 는 데 필요 한 최소 대 가 를 구 하 십시오.두 문자열 A 와 B, 그리고 그들의 길이 와 세 가지 조작 대 가 를 정 합 니 다. A 문자열 을 B 문자열 로 바 꾸 는 데 필요 한 최소 대 가 를 되 돌려 주 십시오.두 줄 의 길이 가 모두 300 보다 작 고 세 세대 의 가 치 는 모두 100 보다 작 음 을 보증한다.테스트 샘플: "abc", 3, "adc", 3, 5, 3, 100 반환: 8
이 문 제 는 앞의 몇 가지 문제 에 비해 더욱 추상 적 입 니 다. 우 리 는 네 가지 상황 을 정의 해 야 합 니 다. 먼저 dp [i] [j] 는 A 문자열 의 앞 i 문 자 를 B 문자열 의 앞 j 문자 로 바 꾸 는 데 필요 한 대 가 를 표시 합 니 다. 첫 번 째 는 A [i] = B [j] 일 때 우 리 는 어떠한 조작 도 하지 않 아 도 다음 문자 의 비교 에 들 어 갈 수 있 습 니 다. 상태 전이 방정식 은 dp [i] [j] = dp [i - 1] [j - 1] 입 니 다.두 번 째 상황 은 A 문자열 의 마지막 문 자 를 삭제 하여 A 문자열 과 B 문자열 을 같 게 하고 상 태 를 dp [i] [j] = dp [i - 1] [j] + c1 로 이전 하 는 것 입 니 다.세 번 째 는 B 열 에 한 문 자 를 삽입 하여 A 열 과 B 열 을 같 게 하 는 것 이다. 즉, B 열 에서 마지막 문 자 를 제거 하고 A 현재 의 A 열 과 같 으 며 방정식 을 dp [i] [j] = dp [i] [j - 1] + c0 으로 옮 기 는 것 이다.네 번 째 는 A 문자열 의 한 문 자 를 수정 하여 A 문자열 과 B 문자열 을 같 게 하 는 것 이다. 즉, A 문자열 과 B 문자열 의 마지막 문 자 는 같 지 않 고 다른 위 치 는 모두 같 으 며 상태 상 태 는 dp [i] [j] = dp [i - 1] [j - 1] + 1 로 이전 하 는 것 이다.뒤의 세 가지 상황 에서 우 리 는 모두 A 문자열 을 B 문자열 로 바 꿀 수 있 지만, 여기 서 요구 하 는 것 은 최소 의 대가 이기 때문에 dp [i] [j] = min (상황 2, 3, 4).자바 버 전의 코드 는 다음 과 같 습 니 다.
    public static int findMinCost(String A, int n, String B, int m, int c0, int c1, int c2) {
        // write code here
        int[][] dp = new int[n+1][m+1];
        for(int i = 0; i <=n; i++) dp[i][0] = i*c0;
        for(int j = 0; j <=m; j++) dp[0][j] = j*c1;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                if(A.charAt(i - 1) == B.charAt(j - 1)){
                    dp[i][j] = dp[i - 1][j - 1];
                }else{
                    dp[i][j] = Math.min(dp[i - 1][j - 1] + c2,Math.min(dp[i][j - 1] + c0,dp[i - 1][j] + c1));
                }
            }
        }
        return dp[n][m];
    }

0 / 1 가방 문제 0 / 1 가방 문 제 는 동적 계획 문제 중의 전형 적 인 문제 설명 입 니 다. 주어진 N 중의 물품 과 가방 입 니 다.아 이 템 i 의 무 게 는 와 이 파이 이 며 그 가 치 는 Vi 이 며 가방 의 용량 은 C 입 니 다.-- 가방 에 들 어 가 는 아 이 템 을 어떻게 선택해 야 가방 에 들 어 가 는 아 이 템 의 총 가 치 를 최대 로 할 수 있 나.아 이 템 을 선택 할 때 각 아 이 템 i 에 대해 서 는 가방 을 넣 거나 가방 을 넣 지 않 는 두 가지 선택 만 있 습 니 다.아 이 템 i 를 여러 번 불 러 올 수도 없고 아 이 템 의 일부분 만 불 러 올 수도 없습니다.이에 따라 이 문 제 는 0 - 1 가방 문제 로 불 린 다.
이 문제 에 대해 우 리 는 최대 가 치 를 Max (N, C) 로 정의 합 니 다. 여기 서 우 리 는 두 가지 상황 으로 나 누 어 상황 을 고려 할 수 있 습 니 다. 하 나 는 가방 에 N 번 째 아 이 템 을 넣 었 습 니 다. 그러면 우 리 는 아직 N - 1 개의 아 이 템 과 C - cn 의 가방 용량 이 남 았 습 니 다. 이런 상황 에서 우리 가 얻 은 가장 큰 가 치 는 Max (N - 1, C - cn) + N * vn 입 니 다.이것 은 바로 위의 문제 의 하위 문제 상황 이다. 2. 가방 에 N 번 째 아 이 템 이 들 어 있 지 않 으 면 우 리 는 N - 1 개의 아 이 템 과 C 의 가방 용량 이 남 았 다. 이런 상황 에서 우리 가 얻 은 가장 큰 가 치 는 Max (N - 1, C) 이다. 위의 분석 을 통 해 우 리 는 dp [i] [j] 가 i 개의 아 이 템 과 j 의 용량 이 있 는 상황 에서 얻 을 수 있 는 가장 큰 가 치 를 정의 할 수 있다.상황 1, 2 를 통 해 상태 이동 방정식 을 쉽게 얻 을 수 있 습 니 다. dp [i] [j] = Max (dp [i - 1] [j - ci] + vi, dp [i - 1] [j]) 를 이해 하기 위해 구체 적 인 0 / 1 가방 인 스 턴 스 를 드 립 니 다.
왕 강 씨 는 오늘 매우 즐 거 웠 습 니 다. 회사 에서 N 위안 의 연말 상 을 주 었 습 니 다.왕 강 은 연말 상 을 쇼핑 에 사용 하기 로 결 정 했 습 니 다. 그 는 사고 싶 은 물건 을 두 가지 로 나 누 었 습 니 다. 메 인 부품 과 첨부 파일, 첨부 파일 은 특정한 메 인 부품 에 속 하 는 것 입 니 다. 첨부 파일 로 분류 되 는 물건 을 사려 면 반드시 이 첨부 파일 에 속 하 는 메 인 부품 을 먼저 사 야 합 니 다.각 주 부품 에는 0 개, 1 개 또는 2 개의 부속품 이 있 을 수 있다.첨부 파일 은 더 이상 자신 만 의 첨부 파일 이 없다.왕 강 은 사고 싶 은 물건 이 많 았 습 니 다. 예산 을 초과 하지 않 기 위해 모든 물건 을 중요 도 를 정 했 습 니 다. 5 등 으로 나 누 었 습 니 다. 정수 1 ~ 5 로 5 등 이 가장 중요 합 니 다.그 는 또 인터넷 에서 모든 물품 의 가격 (모두 10 위안 의 정수 배) 을 찾 아 냈 다.그 는 N 위안 (N 위안 과 같 을 수 있 음) 을 초과 하지 않 는 전제 에서 모든 물품 의 가격 과 중요 도 를 곱 하 는 총계 가 가장 크 기 를 바란다.j 번 아 이 템 의 가격 은 v [j] 이 고 중요 도 는 w [j] 입 니 다. 모두 k 번 아 이 템 을 선 택 했 습 니 다. 번 호 는 j 1, j 2,..., j k 이 고 원 하 는 총 계 는 v [j 1] w [j 1] + v [j 2] * w [j 2] +... + v [j k] * w [j k]] 입 니 다.(그 중 곱 하기) 자바 버 전의 소스 코드 를 직접 드 립 니 다.
import java.util.*;

/**
 * Created by    on 2017/3/26.
 */
public class Main {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (in.hasNext()) {
            String[] moneyAndNum = in.nextLine().split(" ");
            int money = Integer.valueOf(moneyAndNum[0]);
            int n = Integer.valueOf(moneyAndNum[1]);
            int[][] weight = new int[60][3];
            int[][] val = new int[60][3];
            int[][] dp = new int[n+1][money+1];
            int index = 1;
            for(int i = 0; i < n; i++){
                String[] strs = in.nextLine().split(" ");
                int p = Integer.valueOf(strs[0]);
                int w = Integer.valueOf(strs[1]);
                int q = Integer.valueOf(strs[2]);
                if(q == 0){
                    weight[index][0] = p;
                    val[index][0] = w * p;
                    index++;
                }else{
                    if(weight[index - 1][1] == 0){
                        weight[index - 1][1] = p;
                        val[index - 1][1] = w * p;
                    }else{
                        weight[index - 1][2] = p;
                        val[index - 1][2] = w * p;
                    }
                }
            }
            for(int i = 1; i < n + 1; i++){
                for(int j = 1; j < money + 1; j++){
                //j     i   
                    if(weight[i][0] <= j){
                    //dp[i - 1][j]      i   ,dp[i - 1][j - weight[i][0]]     i   
                        dp[i][j] = Math.max(dp[i - 1][j],dp[i - 1][j - weight[i][0]] + val[i][0]);
                    }
                    if(weight[i][0] + weight[i][1] <= j){
                        dp[i][j] = Math.max(dp[i][j],Math.max(dp[i - 1][j],dp[i - 1][j - weight[i][0] - weight[i][1]] + val[i][0] + val[i][1]));
                    }
                    if(weight[i][0] + weight[i][2] <= j){
                        dp[i][j] = Math.max(dp[i][j],Math.max(dp[i - 1][j],dp[i - 1][j - weight[i][0] - weight[i][2]] + val[i][0] + val[i][2]));
                    }
                    if(weight[i][0] + weight[i][1] + weight[i][2] <= j){
                        dp[i][j] = Math.max(dp[i][j],Math.max(dp[i - 1][j],dp[i - 1][j - weight[i][0] - weight[i][1] - weight[i][2]] + val[i][0] + val[i][1] + val[i][2]));
                    }
                }
            }
            System.out.println(dp[n][money]);
        }
    }



}


주식 수익 최대 화 문제 (leetcode 에서 온) 주식 수익 최대 화 문제 1
주식 수익 의 최대 화 문제 2 는 한 배열 이 있다. 배열 중의 i 번 째 수 는 i 일 주식 의 가격 을 나타 낸다. 지금 은 알고리즘 을 설계 하여 최대 화 된 주식 수익 을 얻 도록 요구한다. 여 기 는 가능 한 한 여러 번 의 거래 를 할 수 있 지만 거래 는 교차 할 수 없다. 즉, 주식 을 사기 전에 반드시 이전 주식 을 팔 아야 한다.여기 서 상태 이전 문 제 를 분석 하 겠 습 니 다. i 일 째 에 우 리 는 주식 의 가격 을 관찰 합 니 다. 만약 에 price [i] > price [i - 1] 는 i 일 째 i - 1 일 에 상대 적 으로 수익 이 있다 는 것 을 나타 냅 니 다. 만약 에 우리 가 i 일 째 에 주식 을 팔 면 i - 1 일 에 비해 수익 이 증가 하고 방정식 은 dp [i - 1] + price [i] - 1] - price [i - 1], price [i] < = price [i - 1] 입 니 다. 만약 에 우리 가 i 일 째 에 주식 을 팔 면...손실 이기 때문에 우 리 는 주식 을 계속 보유 하고 있 습 니 다. 즉, 방정식 은 dp [i] = dp [i - 1] 입 니 다.어떤 친구 들 은 곤 혹 스 러 울 수도 있 습 니 다. 여 기 는 매도 조작 만 있 습 니 다. 그러면 언제 주식 을 사 들 였 는 지 어떻게 알 겠 습 니까? 우 리 는 자세히 분석 해 보면 주식 이 하락 할 때 어떠한 조작 도 하지 않 고 수익 도 없 으 며 주식 가격 이 가장 낮 고 상승 하기 시 작 했 을 때 우 리 는 사 들 이기 시 작 했 습 니 다.그리고 주가 가 가장 높 을 때 던 져 요.참고 자바 버 전 코드 를 드 리 겠 습 니 다:
public class Solution {
    public int maxProfit(int[] prices){
        int[] dp = new int[prices.length];
        if(prices.length == 0) return 0;
        dp[0] = 0;
        for(int i = 1; i < prices.length;i++){
            if(prices[i] > prices[i - 1]){
                dp[i] = dp[i - 1] + prices[i] - prices[i - 1];
            }else{
                dp[i] = dp[i - 1];
            }
        }
        return dp[prices.length - 1];
    }
}

**     **

기 존의 분동 은 무게 가 서로 같 지 않 고 각각 m1, m2, m3... mn 이다.각 분동 에 대응 하 는 수량 은 x1, x2, x3... xn 이다.지금 은 이 분동 으로 물체 의 무 게 를 달 아서 얼마나 다른 무 게 를 달 수 있 는 지 물 어 봐 야 한다.
주: 무게 측정 은 0 입력 설명 을 포함 합 니 다. 입력 은 여러 그룹의 테스트 데 이 터 를 포함 합 니 다.
각 그룹의 테스트 데이터:
첫 번 째 줄: n - 분동 수 (범위 [1, 10])
두 번 째 줄: m1 m2 m3... mn - 각 분동 의 무게 (범위 [1, 2000])
세 번 째 줄: x1 x2 x3... xn - 각 분동 의 수량 (범위 [1, 6])
이곳 의 상태 전이 방정식 은 쉽게 얻 을 수 있 으 며, 사용 가능 한 분동 수량 이 0 이 아 닌 상황 에서 w - mi 의 무 게 를 달 수 있다 면 w 의 무게 도 달 수 있다.이 상태 전이 방정식 을 바탕 으로 우 리 는 크기 가 총 무게 인 배열 을 정의 할 수 있 습 니 다. 모든 무 게 를 표시 할 수 있 는 지, 즉 max Weight = mi * xi (0) 를 표시 할 수 있 습 니 다.
import java.util.Scanner;

/**
 * Created by    on 2017/4/23.
 */
public class Main {
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        while(in.hasNext()){
            int n = in.nextInt();
            int[] m = new int[n];
            int[] x = new int[n];
            for(int i = 0; i < n;i++){
                m[i] = in.nextInt();
            }
            for(int i = 0; i < n; i++){
                x[i] = in.nextInt();
            }
            int max = 0;
            for(int i = 0; i < n;i++){
                max += m[i] * x[i];
            }
            int[] dp = new int[max + 1];
            dp[0] = 1;
            for(int i = 0; i < n;i++){
                for(int k = max; k >= 1;k--){
                    for(int j = x[i]; j >= 0;j--){
                        if((k-j * m[i] >= 0) && (dp[k-j * m[i]] == 1)){
                            dp[k] = 1;
                        }
                    }
                }
            }
            int num = 0;
            for(int i = 0; i <= max; i++){
                if(dp[i] == 1){
                    num++;
                }
            }
            System.out.println(num);
        }
    }
}

좋은 웹페이지 즐겨찾기