1. Overview of the backpack problem
As shown in the picture, there is only one difference between the complete backpack and the 01 backpack: you can only take one item of each item in the 01 backpack, but you can take countless items of each item in the complete backpack. To solve the complete knapsack problem, you must first understand the 01 knapsack. If you are unclear, you can read my article 01 knapsack—dynamic programming .
2. Example questions
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. One-dimensional array (rolling array) solution to complete knapsack
1. From 01 backpack to complete backpack
From 01 Knapsack - Dynamic Programming , we can know that a one-dimensional DP array is a simplification of a two-dimensional DP array. Therefore, the two-dimensional DP array is essentially the same as the one-dimensional DP array. This article only introduces the one-dimensional DP array solution to the complete knapsack.
For the 01 backpack, the inner loop j
is traversed backwards from large to small. The reason for this is to prevent dp[j]
the previous elements from being contaminated and avoid the problem of accumulation (each item can only be selected once). For a complete backpack, each item can be selected countless times. j
Traversing from front to back means j
trying to put items into each capacity i
to see if it will increase the total value. It does not pay attention to i
the number of items put in. . Therefore, there is only one difference between the code of the complete backpack and the 01 backpack, which is j
the traversal order.
// 01背包遍历
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]);
}
}
// 完全背包遍历
// 先遍历物品,再遍历背包
for(int i = 0; i < weight.size(); i++) {
// 遍历物品
for(int j = weight[i]; j <= bagWeight ; j++) {
// 遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
2. The difference between 01 backpack and complete backpack—traversal order
The traversal order of 01 backpack is:
In the two-dimensional DP array, you can traverse the items first or the backpack capacity first;
In a one-dimensional DP array, items must be traversed first before traversing the backpack capacity. Only in this way can you ensure that each item is selected only once.
For a complete backpack, there is no restriction that you can only select it once, so is it okay to traverse the backpack capacity first and then traverse the items? The answer is yes. Because it is calculated based on the DP array element corresponding to dp[j]
the subscript . j
Just make sure that the DP array before the subscript j
is calculated. Figure 1 traverses the backpack capacity first and then traverses the items; Figure 2 traverses the items first and then traverses the backpack capacity.
// 先遍历物品,再遍历背包
for(int i = 0; i < weight.size(); i++) {
// 遍历物品
for(int j = weight[i]; j <= bagWeight ; j++) {
// 遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
// 先遍历背包,再遍历物品
for(int j = 0; j <= bagWeight; j++) {
// 遍历背包容量
for(int i = 0; i < weight.size(); i++) {
// 遍历物品
if (j - weight[i] >= 0)
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}