04.03_多重背包

多重背包

问题描述

个物品,每个物品有重量 、价值 和数量限制 。现在有一个容量为 的背包,每个物品最多选择 次,求解在不超过背包容量的情况下,能够装入物品的最大价值。

与其他背包的区别

  1. 01背包:每个物品最多选择1次
  2. 完全背包:每个物品可以选择无限次
  3. 多重背包:每个物品可以选择

基本解法

状态定义

  • 表示考虑前 个物品,背包容量为 时能获得的最大价值

状态转移方程

dp[i][j] = max(dp[i-1][j-k*w[i]] + k*v[i])
其中 k∈[0,s[i]] 且 k*w[i] ≤ j

二进制优化

将每个物品的数量 进行二进制拆分,转化为01背包问题。

例如:数量为13可以拆分为1,2,4,6,因为13=1+2+4+6

C++ 实现(二进制优化)

int multipleKnapsack(vector<int>& w, vector<int>& v, vector<int>& s, int W) {
    int n = w.size();
    vector<int> dp(W + 1, 0);
    
    for (int i = 0; i < n; i++) {
        // 二进制拆分
        int num = s[i];
        for (int k = 1; num > 0; k <<= 1) {
            int amount = min(k, num);
            num -= amount;
            // 01背包过程
            for (int j = W; j >= w[i] * amount; j--) {
                dp[j] = max(dp[j], dp[j - w[i] * amount] + v[i] * amount);
            }
        }
    }
    
    return dp[W];
}

Java 实现

class Solution {
    public int multipleKnapsack(int[] w, int[] v, int[] s, int W) {
        int n = w.length;
        int[] dp = new int[W + 1];
        
        for (int i = 0; i < n; i++) {
            int num = s[i];
            for (int k = 1; num > 0; k <<= 1) {
                int amount = Math.min(k, num);
                num -= amount;
                for (int j = W; j >= w[i] * amount; j--) {
                    dp[j] = Math.max(dp[j], dp[j - w[i] * amount] + v[i] * amount);
                }
            }
        }
        
        return dp[W];
    }
}

Python 实现

def multipleKnapsack(w: List[int], v: List[int], s: List[int], W: int) -> int:
    n = len(w)
    dp = [0] * (W + 1)
    
    for i in range(n):
        num = s[i]
        k = 1
        while num > 0:
            amount = min(k, num)
            num -= amount
            for j in range(W, w[i] * amount - 1, -1):
                dp[j] = max(dp[j], dp[j - w[i] * amount] + v[i] * amount)
            k <<= 1
    
    return dp[W]

时间复杂度分析

  • 朴素解法:
  • 二进制优化:
  • 空间复杂度:

优化方法

  1. 二进制拆分:

    • 将每个物品拆分成二进制数量
    • 显著减少状态转移的次数
  2. 单调队列优化:

    • 对于较大的数量可以使用单调队列
    • 时间复杂度可以优化到

应用场景

  1. 库存管理问题
  2. 资源分配规划
  3. 生产计划制定
  4. 投资组合优化
  5. 商品促销策略

注意事项

  1. 数量限制的处理
  2. 二进制拆分的实现
  3. 整数溢出问题
  4. 内存使用限制
  5. 特殊情况处理
test1 文章被收录于专栏

test11

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务