问题描述

N种物品和一个容量为V 的背包。第i种物品最多有Mi件可用,每件耗费的空间是Ci ,价值是Wi 。求解将哪些物品装入背包可使这些物品的耗费的空间 总和不超过背包容量,且价值总和最大。

例:物品为:


重量 价值 个数
物品0 1 15 2
物品1 3 20 2
物品2 4 30 3

将物品的个数摊开则转化为 0-1背包 问题

解题方法

先将多个同一物品摊开,再通过 0-1背包 解决
C++代码:

  1. void test_multi_pack() {
  2. vector<int> weight = {1, 3, 4};
  3. vector<int> value = {15, 20, 30};
  4. vector<int> nums = {2, 3, 2};
  5. int bagWeight = 10;
  6. for (int i = 0; i < nums.size(); i++) {
  7. while (nums[i] > 1) { // nums[i]保留到1,把其他物品都展开
  8. weight.push_back(weight[i]);
  9. value.push_back(value[i]);
  10. nums[i]--;
  11. }
  12. }
  13. vector<int> dp(bagWeight + 1, 0);
  14. for(int i = 0; i < weight.size(); i++) { // 遍历物品
  15. for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
  16. dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
  17. }
  18. }
  19. }
在 0-1 背包 内部遍历不同数量的结果<br />**C++代码:**
void test_multi_pack() {
    vector<int> weight = {1, 3, 4};
    vector<int> value = {15, 20, 30};
    vector<int> nums = {2, 3, 2};
    int bagWeight = 10;
    vector<int> dp(bagWeight + 1, 0);

    for(int i = 0; i < weight.size(); 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]);
            }
        }
    }
}