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