01 Backpack—Dynamic Programming

1. Overview of the backpack problem:

Please add image description

2. Violent solution:

weight value
Item 0 1 15
Item 1 3 20
Item 2 4 30

The maximum capacity of the backpack is 4.

Each item has two states, "take" or "not take". The backtracking method can be used to violently enumerate the permutations and combinations of the status of all items, and compare it with the maximum capacity of the backpack to find the maximum value. The time complexity is O ( 2 n ) O(2^n)O(2n )is at exponential level, so dynamic programming solution is required for optimization.

3. Two-dimensional DP array solution 01 backpack

1. Meaning of DP array

dp[i][j]: The maximum value obtained by taking [0,i]any item with the number and placing it in a backpack with a capacity of .j

2. Recursion formula (pair dp[i][j])

  1. No items left i:dp[i][j]=dp[i-1][j]
  2. Put items i:dp[i][j]=dp[i-1][j-weight[i]] + value[i]

dp[i][j]In the end, the larger value of placing the item ior not placing the item should be taken.i

Therefore,dp[i][j]=max(dp[i-1][j], dp[i-1][j-weight[i]]+value[i])

3.DP array analysis

Please add image description
As shown in the figure, for dp[i][j](red table), its value is obtained from two directions:

  1. dp[i][j]=dp[i-1][j], obtained from red arrow No. 1;
  2. dp[i][j]=dp[i-1][j-weight[i]] + value[i], obtained by arrow No. 2. The specific initial position of arrow No. 2 is weight[i]determined by.

[i-1]Therefore, it must be known when solving the DP array , so the first line must be initialized when initializing the DP array.

The first column does not need to be initialized, just use ifjudgment j-weight[i] > 0 .

In summary, during initialization, only the first row is initialized, and the rest of the positions do not need to be initialized.

For this question, the initialization array is:
Please add image description

4. Traversal order

i traverses the items first and then the backpack

Please add image description
The essence of this method is to traverse rows and test each item one by one from capacity 0to capacity. jIt can be obtained by parsing the DP array. All the data in it dp[i][j]must be known when searching dp[i-1][0~j], and this has been obtained in the previous loop. Therefore, this traversal method is feasible.

ii First traverse the backpack and then traverse the items

Please add image descriptionThe essence of this method is to traverse in columns and test each capacity one by one from item 0to item. iIt can be obtained by parsing the DP array. All the data in it dp[i][j]must be known when searching dp[i-1][0~j], and this has been obtained in the previous loop. Therefore, this traversal method is feasible.

5. Code:

void knapsack () {
    
    
    vector<int> weight = {
    
    1, 3, 4};  // 物品重量
    vector<int> value = {
    
    15, 20, 30};  // 物品价值
    int bagweight = 4;  // 背包的最大容量
    // 创建二维数组
    vector<vector<int>> dp(weight.size(), vector<int>(bagweight + 1, 0));
    // 初始化
    for (int j = weight[0]; j <= bagweight; j++) {
    
    
        dp[0][j] = value[0];
    }
    // 先遍历物品
    for(int i = 1; i < weight.size(); i++) {
    
     // 遍历物品
        for(int j = 0; j <= bagweight; j++) {
    
     // 遍历背包容量
            if (j < weight[i]) dp[i][j] = dp[i - 1][j];
            else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
        }
    }
    // 先遍历背包
    // for(int j = 0; j <= bagweight; j++) { // 遍历背包容量
    //    for(int i = 1; i < weight.size(); i++) { // 遍历物品
    //        if (j < weight[i]) dp[i][j] = dp[i - 1][j];
    //         else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
    //     }
    // }
    cout << dp[weight.size() - 1][bagweight] << endl;
}

4. One-dimensional DP array (rolling array) solution to 01 backpack

1. Meaning of DP array

It can be seen from the traversal diagram of the two-dimensional DP array that the solution dp[i][j]is completely using the data of the previous row (or column) of the DP array, and dp[i][j]does not care about the subsequent content at all. Therefore, you can consider overwriting the data of the previous row (or previous column) to the current row, and the calculation can be completed using one row (or one column). This is the idea of ​​the one-dimensional DP array in this question.

This question is defined as the maximum value of items that can be contained dp[j]in a backpack with a capacity of (equivalent to compressing a two-dimensional array into one row).j

2. Recursion formula

  1. Do not put items i: dp[j]=dp[j](You can dp[j]regard the data after the equal sign as the data of the previous row, but it only overwrites the current row)
  2. Putting items i: dp[j]=dp[j-weight[i]]+value[i](You can think of dp[j-weight[i]]what is after the equal sign as the data of the previous row, but it just overwrites the current row)

dp[j]=max(dp[j], dp[j-weight[i]]+value[i])

3.DP array initialization

It can be seen from the definition of the array that you dp[j]only need to know the data in front of it. Think about it, the "front" data is that the backpack contains no objects. Therefore, just set all elements of the DP array to 0.

4. Traversal order

Because the value of the current DP array can be seen as an overlay of the previous row, in order to keep the dp[j]previous elements "clean", jflashback traversal should be used during traversal.
Please add image description
As shown in the figure, blue represents the updated value of the current row, red represents the value being requested by the current row, and green represents the value of the previous row that has not yet been updated. Traversing from back to front ensures that dp[j]when updating, the previous values ​​will not be changed. If forward traversal is used, it is equivalent to the dp[j]previous value being the value of the current row (this statement is also incorrect, ithe value of the item is accumulated), and the recursive formula does not hold.

Assume that the item weight {1, 1}, value {5, 10}, and maximum capacity of the backpack are 4. As shown in the figure, if forward order traversal is used to
Please add image description
update DP in the second row, since dp[j]the previous data has been contaminated, dp[j]the value of item 1 is accumulated every time it is updated. During flashback, since the previous data has not been deleted 污染, no cumulative error will occur. As shown in the picture:
Please add image description

5.Code

void test_1_wei_bag_problem() {
    
    
    vector<int> weight = {
    
    1, 3, 4};
    vector<int> value = {
    
    15, 20, 30};
    int bagWeight = 4;
    // 初始化
    vector<int> dp(bagWeight + 1, 0);
    for(int i = 0; i < weight.size(); i++) {
    
     // 遍历物品
        for(int j = bagWeight; j >= weight[i]; j--) {
    
     // 遍历背包容量
            dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
        }
    }
    cout << dp[bagWeight] << endl;
}

Guess you like

Origin blog.csdn.net/qq_44733706/article/details/129165805