背包问题
01 背包
有n件物品和一个最多能背重量为 w 的背包。第 i 件物品的重量是 weight[i]
,得到的价值是 value[i]
。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
动规五部曲:
确定 dp 数组以及下标的含义,
dp[i][j]
表示从[0, i]
物品中任意选择,放进容量为j
的背包,能够获得的最大价值确定递推公式:
dp[i] [j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
,其中j-weight[i]
表示要腾出来weight[i]
大小的空间。使用滚动数组的话,递推公式为:
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
dp 数组初始化
确定遍历顺序
举例推导 dp 数组
一维滚动数组解法:
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;
}
int main() {
test_1_wei_bag_problem();
}
完全背包问题
有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次),求解将哪些物品装入背包里物品价值总和最大。
完全背包问题和 01 背包问题唯一不同的地方是物品有无限个。
一维滚动数组解法:
// 先遍历物品,在遍历背包
void test_CompletePack() {
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 = weight[i]; j <= bagWeight; j++) { // 遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
cout << dp[bagWeight] << endl;
}
int main() {
test_CompletePack();
}