The Knapsack Problem: Recursive Implementation and Dynamic Programming Implementation

Problem Description

Given n items, the weight of the item is w[i], and the value of the item is v[i]. Now select items to put into the backpack, assuming that the maximum weight that the backpack can bear is W, how to choose the items in the backpack so that the total value of the items in the backpack is the largest?

In class today, I mentioned that for a 01 backpack, each item can be put or not put in two states. I suddenly thought that I could use a recursive method to solve this problem, so I came up with this article. The general method is dynamic programming, which will be explained later.

recursive implementation

Idea analysis

first picture
insert image description here

Why can a knapsack problem draw a tree graph?
Don't worry, let me speak slowly:

Each node in the figure represents a state, and each edge represents an operation. The
edge connecting the left subtree of each node is 1, and the edge connecting the right subtree is 0:
1 means put the item in the backpack,
0 means not The item is put into the backpack.
The two left children are actually the new state obtained after performing different operations on the same element.

A characteristic of a tree is that a child of a tree is still a tree. Then this provides the possibility for us to implement the problem recursively.

(1) When there is no leaf node (the last element of the weight array and value array has not yet been put into the backpack), call this function recursively to operate on the next element (2) When a leaf node is
encountered point (that is, when the weight array and the value array reach the end), encounter the recursive exit, and start to unstack

Code

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);
    }
}

Dynamic programming implementation

Idea analysis

Let's first consider an instance defined by the first i items (1 ≤ i ≤ n), whose weights are w 1 , . . . wi w_1,...w_iw1,...wi, the values ​​are respectively v 1 , . . . vi v_1,...v_iv1,...vi, the weight of the knapsack is j (1 ≤ j ≤ W). Let dp(i, j) be the total value of items in the optimal solution for this instance, that is, the total value of the most valuable subset of the first i items that can fit into a knapsack of capacity j. The subset of the first i items that can be put into a knapsack with a load capacity of j can be divided into two categories; the subset that includes the i-th item and the subset that does not include the i-th item

(1) In the subset that does not include the i-th item, the value of the optimal subset is dp(i - 1,j)
(2) In the subset that includes the i-th item (this must satisfy: j − wij - w_ijwi≥ 0), the optimal subset is the item that can be placed in the first i - 1 items with a load capacity of j − wij - w_ijwiThe optimal subset of the knapsack of . The total value of this optimal subset is vi + dp ( i − 1 , j − wi ) v_i + dp(i-1,j-w_i)vi+dp(i1,jwi)

状态转移方程如下:
d p ( i , j ) = { m a x { d p ( i − 1 , j ) , v i + d p ( i − 1 , j − w i ) } , j − w i ≥ 0 d p ( i − 1 , j ) , j − w i < 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{cases} dp(i,j)={ max{ dp(i1,j),vi+dp(i1,jwi)},dp(i1,j),jwi0jwi<0

Code

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];
    }
}

There are still many optimizations for the dynamic programming of the knapsack problem, and I only record the most basic one here.
The following nine lectures on backpacks have a very detailed explanation of the backpack problem. Welcome to download
the nine lectures on backpacks.

Guess you like

Origin blog.csdn.net/BWQ2019/article/details/110563653