多重背包问题,常用解法分析与比较
🎯 多重背包问题三大解法总结(C++实现 + 中文讲解 + 题目推荐)
✅ 问题类型 Problem Type:
多重背包(Bounded Knapsack)
每种物品最多只能选 \(s_i\) 次,不能无限制选择。
🧠 解法一:朴素多重背包(Simple Expansion)
时间复杂度: \(O(n \times s \times m)\)
操作估计: ~30e6
适用场景: \(s\) 较小时,代码最直观,适合入门和验证正确性。
代码 C++:
for (int i = 0; i < n; i++) {
    int v, w, s;
    cin >> v >> w >> s;
    for (int k = 0; k < s; k++) {
        for (int j = m; j >= v; j--) {
            dp[j] = max(dp[j], dp[j - v] + w);
        }
    }
}
⚙️ 解法二:二进制拆分(Binary Decomposition)
时间复杂度: \(O(n \log s \times m)\)
操作估计: ~12e6
适用场景: \(s\) 较大时的实用方案,大幅减少物品数。
代码 C++:
for (int i = 0; i < n; i++) {
    int v, w, s;
    cin >> v >> w >> s;
    for (int k = 1; k <= s; k <<= 1) {
        for (int j = m; j >= k * v; j--) {
            dp[j] = max(dp[j], dp[j - k * v] + k * w);
        }
        s -= k;
    }
    if (s > 0) {
        for (int j = m; j >= s * v; j--) {
            dp[j] = max(dp[j], dp[j - s * v] + s * w);
        }
    }
}
🚀 解法三:单调队列优化(Monotonic Queue)
时间复杂度: \(O(n \times m)\)
操作估计: ~3e6
适用场景: \(m, s\) 较大时最优选择,适合竞赛或极限测试。
核心思想:
按物品体积 \(v\) 的余数对容量分组,对每组进行滑动窗口最大值优化。
代码 C++:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int M = 6005;
int dp[M], g[M], q[M];
int main() {
    int n, m;
    cin >> n >> m;
    memset(dp, 0, sizeof(dp));
    for (int i = 0; i < n; i++) {
        int v, w, s;
        cin >> v >> w >> s;
        memcpy(g, dp, sizeof(dp));
        for (int r = 0; r < v; r++) {
            int head = 0, tail = -1;
            for (int t = 0; r + t * v <= m; t++) {
                int j = r + t * v;
                while (head <= tail && t - q[head] > s) head++;
                while (head <= tail && g[j] - t * w >= g[r + q[tail] * v] - q[tail] * w) tail--;
                q[++tail] = t;
                dp[j] = g[r + q[head] * v] - q[head] * w + t * w;
            }
        }
    }
    cout << dp[m] << endl;
    return 0;
}
📊 三种解法对比表
| 解法编号 | 方法 | 时间复杂度 | 操作估计 | 优点 | 适用场景 | 
|---|---|---|---|---|---|
| 解法1 | 枚举物品个数 | \(O(n \times s \times m)\) | ~30e6 | 简单直接 | s 小、教学/验证 | 
| 解法2 | 二进制优化 | \(O(n \log s \times m)\) | ~12e6 | 降低冗余、效率提升 | s 中等 | 
| 解法3 | 单调队列优化 | \(O(n \times m)\) | ~3e6 | 效率最优,竞赛推荐 | s/m 较大,性能要求高 | 
🧪 LeetCode & 洛谷相关题目推荐练习
🔷 LeetCode:
| 题号 | 题目名称 | 类型 | 链接 | 
|---|---|---|---|
| 322 | 零钱兑换 | 完全背包 | 传送门 | 
| 518 | 零钱兑换 II | 完全背包 + 组合数 | 传送门 | 
| 474 | 一和零 | 多维 0-1 背包 | 传送门 | 
| 879 | 盈利计划 | 多重背包 | 传送门 | 
🔶 洛谷:
| 题号 | 题目名称 | 类型 | 链接 | 
|---|---|---|---|
| P1060 | 开心的金明 | 多重背包 | 传送门 | 
| P1776 | 宝物筛选 | 多重背包 | 传送门 | 
| P1833 | 樱花 | 多重背包 | 传送门 | 
✅ 总结
- 💡 解法1: 简洁直观,适合入门。
 - ⚙️ 解法2: 实用性强,建议掌握。
 - 🚀 解法3: 性能最优,竞赛优选。
 - 📚 练习题覆盖完整背包体系,含完全、0-1、多重、多维背包题。
 
需要我将这份内容导出为 Markdown 文件、PDF 或 Word 教案格式,请随时告诉我。也可补充 Python 版本、更多背包题型对比练习题。
                    
                
                
            
        
浙公网安备 33010602011771号