01背包:n种物品,每种物品只有1个
完全背包:n种物品,每种物品无限个
多重背包:n种物品,每种物品个数各不相同
dp[i][j]含义:i为[0,i]区间内的物品,任取,放到容量为j的背包里,最大价值dp[i][j],如果不放当前第i个物品,那么dp[i][j]就等于dp[i-1][j],和前面物品一样;如果放入当前物品,那么为了放入当前物品,背包预留空间至少要为j-weight[i],同时为了让背包内尽可能的多放物品,不留余地,空出来的位置,刚好够当前物品重量就够了,所以dp[i][j]等于dp[i-1][j-weight[i]]+value[i]。放不放入,取最大值,dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i])i-1,j同样依赖于前面的值。因此i=0和j=0时,都需要初始化。i为0,说明只有物品0,不论重量j取多少,只要大于等于当前重量,那么价值就是物品0的价值。如果j为0,说明背包容量为0,任何物品都放不下,价值总是为0void test_2_wei_bag_problem1() {vector weight = {1, 3, 4};vector value = {15, 20, 30};int bagweight = 4;// 二维数组vector> dp(weight.size(), vector(bagweight + 1, 0));// 初始化for (int j = weight[0]; j <= bagweight; j++) {dp[0][j] = value[0];}// weight数组的大小 就是物品个数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]);}}cout << dp[weight.size() - 1][bagweight] << endl;
}int main() {test_2_wei_bag_problem1();
}
观察dp递推公式,只看i,i只依赖于i-1,也就是只依赖于前一行,那就可以将二维降为一维。
dp[j]的含义,容量为j的背包,所背的最大价值为dp[j]dp[j]=dp[j],就是第i-1号物品的最大价值;放物品i,dp[j]=dp[j-weight[i]]+value[i]。同样,要取最大值dp[0]=0,对于非0下标,因为dp[j]的值要和其本身比大小,所以取非负的最小值就可以了,即全部初始化为0void test_1_wei_bag_problem() {vector weight = {1, 3, 4};vector value = {15, 20, 30};int bagWeight = 4;// 初始化vector 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;
}