배낭 문제: 재귀 구현 및 동적 프로그래밍 구현

문제 설명

n개의 항목이 주어지면 항목의 가중치는 w[i]이고 항목의 값은 v[i]입니다. 이제 배낭이 견딜 수 있는 최대 무게를 W라고 가정하고 배낭에 넣을 아이템을 선택합니다. 배낭에 있는 아이템의 총 가치가 최대가 되도록 배낭에 있는 아이템을 선택하는 방법은 무엇입니까?

오늘 수업시간에 01백팩은 2가지 상태로 물건을 넣고 안넣을 수 있다고 말씀드렸는데, 문득 재귀적인 방법으로 이 문제를 해결할 수 있을 것 같아 이 글을 쓰게 되었습니다. 일반적인 방법은 나중에 설명할 동적 프로그래밍입니다.

재귀 구현

아이디어 분석

첫 번째 사진
여기에 이미지 설명 삽입

배낭 문제가 트리 그래프를 그릴 수 있는 이유는 무엇입니까?
걱정하지 마세요. 천천히 말하겠습니다.

그림의 각 노드는 상태를 나타내고 각 에지는 작업을 나타내며
각 노드의 왼쪽 하위 트리를 연결하는 가장자리는 1이고 오른쪽 하위 트리를 연결하는 가장자리는 0
입니다
. 배낭에 아이템을 넣었습니다.
두 개의 왼쪽 자식은 실제로 동일한 요소에 대해 다른 작업을 수행한 후 얻은 새로운 상태입니다.

나무의 특성은 나무의 자식이 여전히 나무라는 것입니다. 그런 다음 이것은 문제를 재귀적으로 구현할 수 있는 가능성을 제공합니다.

(1) 리프 노드가 없을 때(가중치 배열과 값 배열의 마지막 요소가 아직 배낭에 넣지 않은 경우) 이 함수를 재귀적으로 호출하여 다음 요소에 연산을 수행합니다. (2) 리프 노드를 만난
시점 (즉, 가중치 배열과 값 배열이 끝에 도달할 때) 재귀 종료를 만나고 언스택을 시작합니다.

암호

public class Bag {
    
    
    public static void main(String[] args) {
    
    
        int[] weight = new int[]{
    
    16,15,15}; //重量
        int[] value = new int[]{
    
    45,25,25};  //价值
        int capacity = 30;                  //背包容量
        int max1 = maxValue(weight, value, 0, capacity, 0, true);
        int max2 = maxValue(weight, value, 0, capacity, 0, false);
        System.out.println(Math.max(max1, max2));
    }

    public static int maxValue(int[] weight, int[] value, int i, int surplusCapacity,int nowValue, boolean isPutIn){
    
    
        if(i >= weight.length){
    
         //递归出口,越界时返回当前价值
            return nowValue;
        }
        //剩余容量大于当前物品的重量
        if( isPutIn && surplusCapacity >= weight[i]){
    
    
            nowValue += value[i];           //更新当前价值
            surplusCapacity -= weight[i];   //更新当前容量
        }
        int max1, max2;
        /*假如可以放入,假如的原因是不一定能放入*/
        max1 = maxValue(weight, value, i+1, surplusCapacity, nowValue, true);
        /*不想放入*/
        max2 = maxValue(weight, value, i+1, surplusCapacity, nowValue, false);
        return Math.max(max1,max2);
    }
}

동적 프로그래밍 구현

아이디어 분석

먼저 가중치가 w 1 , ... wi w_1,...w_i 인 첫 번째 i 항목(1 ≤ i ≤ n)에 의해 정의된 인스턴스를 고려해 보겠습니다.1,. . . , 값은 각각 v 1 ,...vi v_1,...v_iV1,. . . V, 배낭의 무게는 j(1 ≤ j ≤ W)입니다. dp(i, j)는 이 인스턴스에 대한 최적 솔루션의 항목의 총 값, 즉 용량 j의 배낭에 들어갈 수 있는 첫 번째 i 항목의 가장 가치 있는 하위 집합의 총 값이라고 합니다. 적재 용량이 j인 배낭에 넣을 수 있는 첫 번째 i개의 항목의 부분 집합은 두 가지 범주로 나눌 수 있습니다: i번째 항목을 포함하는 부분 집합과 i번째 항목을 포함하지 않는 부분 집합

(1) i번째 항목을 포함하지 않는 부분 집합에서 최적 부분 집합의 값은 dp(i - 1,j)입니다. (2)
i번째 항목을 포함하는 부분 집합에서 (이는 다음을 충족해야 합니다. j − wij - w_i제이-≥ 0), 최적의 부분 집합은 j − wij - w_i 의 로드 용량으로 첫 번째 i - 1 항목에 배치할 수 있는 항목입니다.제이-의 배낭의 최적 부분집합. 이 최적 부분집합의 총 값은 vi + dp ( i − 1 , j − wi ) v_i + dp(i-1,j-w_i)V+dp ( 나는 _-1 ,제이-)

状态转移方程如下:
dp (i , j ) = { max { dp ( i − 1 , j ) , vi + dp ( i − 1 , j − wi ) } , j − wi ≥ 0 dp ( i − 1 , j ) , j − wi < 0 dp(i ,j) = \begin{cases} max\{dp(i-1,j),v_i + dp(i-1,j-w_i)\},& \text{ $j-w_i≥0$}\\ dp(i-1,j),& \text{$j-w_i < 0$} \end{케이스}dp ( 나는 , _j )={ m a x { d p ( 나는-1 ,j ) ,V+dp ( 나는 _-1 ,제이-) } ,dp ( 나는 _-1 ,j ) ,제이-0제이-<0

암호

import static java.lang.Integer.max;

public class Bag {
    
    
    public static void main(String[] args) {
    
    
        int result = maxValue(new int[]{
    
    16,15,15},new int[]{
    
    45,25,25},30);

        System.out.println(result);
    }
    public static int maxValue(int[] weight, int[] value,int capacity){
    
    
        int n = weight.length;         //物品个数
        int [][]dp = new int[n+1][capacity+1];
        dp[0][0] = 0;
        for(int i = 1; i < n+1; i++){
    
    
            for(int j = 1; j < capacity+1; j++){
    
    
                if( j - weight[i-1] >= 0 ){
    
     //可以放得下当前物品
                    dp[i][j] = max(dp[i-1][j],value[i-1]+dp[i-1][j-weight[i-1]]);
                }else{
    
    
                    dp[i][j] = dp[i-1][j];
                }
            }
        }
        return dp[n][capacity];
    }
}

배낭 문제의 동적 프로그래밍에는 여전히 많은 최적화가 있으며 여기에는 가장 기본적인 것만 기록합니다.
배낭에 대한 다음 9개의 강의는 배낭 문제에 대한 매우 자세한 설명이 있습니다.
백팩에 대한 9개의 강의를
다운로드하는 것을 환영합니다 .

Supongo que te gusta

Origin blog.csdn.net/BWQ2019/article/details/110563653
Recomendado
Clasificación