多重背包问题,常用解法分析与比较

🎯 多重背包问题三大解法总结(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 版本、更多背包题型对比练习题。

posted @ 2025-06-05 09:54  kkman2000  阅读(112)  评论(0)    收藏  举报