多重背包

多重背包

问题描述

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

与其他背包的区别

  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. 特殊情况处理

经典例题

  1. 【模板】多重背包
  2. 称砝码
牛客代码笔记-牛栋 文章被收录于专栏

汗牛充栋,学海无涯。<br/> 内含算法知识点讲解,以及牛客题库精选例题。<br/> 学习算法,从牛栋开始。

全部评论

相关推荐

不愿透露姓名的神秘牛友
06-10 15:24
高考前一晚在OPPO手机上设置了早上5:30的闹钟,然而闹钟并未按时响起。直到妈妈做好早餐后,在6:27打开手机才发现闹钟未触发,“气得早上饭都没吃”。资本家你赢了
永不遗忘:我来解释一下 :Oppo 手机晚上两点会自动进行系统更新,这个系统更新会重置掉所有设置好的闹钟,而且他也不会告诉你,而且只有 Oppo 会这样,华为苹果小米三星都不会
点赞 评论 收藏
分享
见见123:简历没有啥问题,是这个社会有问题。因为你刚毕业,没有工作经历,现在企业都不要没有工作经历的。社会病了。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务