多重背包

多重背包

问题描述

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

与其他背包的区别

  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/> 学习算法,从牛栋开始。

全部评论

相关推荐

吐泡泡的咸鱼:我也工作了几年了,也陆陆续续面试过不少人,就简历来说,第一眼学历不太够,你只能靠你的实习或者论文或者项目经历,然后你没有论文,没有含金量高的比赛和奖项,只能看实习和项目,实习来说,你写的实习经历完全不清楚你想找什么工作?行研?数据分析?且写的太少了,再看项目,这些项目先不说上过大学读过研究生的都知道很水,然后对你想找的岗位有什么帮助呢?项目和实习也完全不匹配啊,你好像在努力将你所有的经历都放在简历里想表现你的优秀,但是对于你想找的岗位来说,有什么用呢?最后只能获得岗位不匹配的评价。所以你需要明白你想要找的岗位要求是什么,是做什么的,比如产品经理,然后再看你的经历里有什么匹配的上这个岗位,或者对这个岗位以及这个岗位所在的公司有价值,再写到你的简历上
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务