题目描述
有N种物品和一个容量为V 的背包。第i种物品最多有Mi件可用,每件耗费的空间是Ci ,价值是Wi 。求解将哪些物品装入背包可使这些物品的耗费的空间 总和不超过背包容量,且价值总和最大。
思路分析
区别于完全背包和简单的01背包问题,多重背包问题既不是每个物品只有一件,又不是每个物品有无数件,而是每件物品有相应的限制数量。在这样的限制数量下求背包里的最大价值。但是可以通过将物品数量展开将问题转变成01背包问题。
转变成如下:
按照动态规划五部曲:
- 确定dp[i][j]的含义:当容器体积为j的时候,从下标为1-i的物品中选取物品,使得最终的背包总价值最大
- 确定递推关系,对于当前物品i有两种情况,那就是放或者不放。
如果放,那么当前的dp[i][j]=dp[i-1][j-weight[i]]+value[i],也就是当背包容量减少物品i的时候的最大价值加上i的价值
如果不放,那么就延续上一个dp[i-1][j]
- 初始化,对于dp[i][0],由于背包容量为0,不管怎么选最终价值都不会超过0,因此将dp[i][0]全部初始化为0;对于dp[0][0],也同样是0。其他的对于dp[0][j],价值就是value[0]。如此一来初始化完毕!
- 遍历顺序选择按照物品的顺序进行遍历
- 带入验证
代码展示
int main() {
int bagWeight,n;
cin >> bagWeight >> n;
vector<int> weight(n, 0);
vector<int> value(n, 0);
vector<int> nums(n, 0);
for (int i = 0; i < n; i++) cin >> weight[i];
for (int i = 0; i < n; i++) cin >> value[i];
for (int i = 0; i < n; i++) cin >> nums[i];
vector<int> dp(bagWeight + 1, 0);
for(int i = 0; i < n; i++) { // 遍历物品
for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量,还是老样子,倒序遍历
// 以上为01背包,然后加一个遍历个数
for (int k = 1; k <= nums[i] && (j - k * weight[i]) >= 0; k++) { // 遍历个数
dp[j] = max(dp[j], dp[j - k * weight[i]] + k * value[i]);
}
}
}
cout << dp[bagWeight] << endl;
}