野牛程序员讲少儿编程之【超神版】——多重背包 + 单调队列优化!(爆炸提速版)
作者:野牛程序员:2025-04-27 18:15:17算法阅读 2307
野牛程序员讲少儿编程之【超神版】——多重背包 + 单调队列优化!(爆炸提速版)
? 野牛程序员讲少儿编程之【超神版】——多重背包 + 单调队列优化!(爆炸提速版)
? 为什么又来一个更高级的?
之前的「二进制优化」,已经能处理中等数量了。
但是!
如果物品超级多,比如每种物品有上万件,背包容量又特别大,
就算是二进制优化,还是有点吃力。
所以,真正的背包王者会用——
? 单调队列优化(Monotonic Queue Optimization)
这种方法就像是:
把所有可能性排成一个整齐的队伍?♂️?♀️
快速挑出最有价值的选择!?
不用每次一个个试!
超大数据量,也能飞快飞快飞快处理!⚡⚡⚡
? 代码展示(带超详细注释版)
#include <iostream>
#include <vector>
#include <deque>
using namespace std;
/**
* 多重背包 + 单调队列优化
* @param W 背包总容量
* @param weights 每种宝贝的重量
* @param values 每种宝贝的价值
* @param counts 每种宝贝的数量
* @return 最大能获得的价值
*/
int multipleKnapsackQueue(int W, vector<int>& weights, vector<int>& values, vector<int>& counts) {
int n = weights.size();
vector<int> dp(W + 1, 0); // dp[w] 表示容量为 w 时的最大价值
for (int i = 0; i < n; i++) {
int weight = weights[i];
int value = values[i];
int count = counts[i];
// 对同余系分组处理
for (int mod = 0; mod < weight; mod++) {
deque<int> q; // 单调队列,存放的是 背包容量索引
for (int k = mod; k <= W; k += weight) {
// 保证队列头部元素在合理数量范围内
if (!q.empty() && (k - q.front()) / weight > count) {
q.pop_front();
}
// 计算当前要比较的值
int current = dp[k] - (k / weight) * value;
// 队列保持单调递减,弹出尾部比 current 小的元素
while (!q.empty()) {
int prev = q.back();
if (dp[prev] - (prev / weight) * value <= current) {
q.pop_back();
} else {
break;
}
}
q.push_back(k);
// 更新 dp[k]
int best = q.front();
dp[k] = dp[best] + (k - best) / weight * value;
}
}
}
return dp[W];
}
int main() {
// 宝贝的重量(kg)
vector<int> weights = {2, 3, 5};
// 宝贝的价值(元)
vector<int> values = {200, 300, 500};
// 每种宝贝的最大数量
vector<int> counts = {100, 50, 20}; // 有很多很多件!
// 背包总容量(kg)
int W = 1000;
cout << "最多可以获得价值:" << multipleKnapsackQueue(W, weights, values, counts) << " 元" << endl;
return 0;
}? 这段代码到底在干什么?
| 步骤 | 解释 |
|---|---|
| 1 | 每种物品按余数分组,比如对重量取模 |
| 2 | 每组使用一个单调队列,专门找最佳选择 |
| 3 | 队列里只保存有可能成为最优答案的容量 |
| 4 | 每次只用看看队头,马上拿到最棒的答案 |
| 5 | 保证不会超过物品数量限制 |
简单说,就是:让背包问题变成选队列里最牛的那个人!
? 小剧场时间
小明背着超级大的背包去超市,
商品太多了,看得眼睛都花了。?这时候,聪明的野牛程序员告诉他:
「不用全都看!只挑最便宜又最好的那几个,直接塞进去!」?小明一下子装了最多的宝贝,满载而归!?✨
? 为什么单调队列这么猛?
| 项目 | 二进制优化 | 单调队列优化 |
|---|---|---|
| 适用情况 | 中等数量 | 超大数量 |
| 速度 | 很快 | 更快 |
| 适合容量 | 一般背包大小 | 超级大背包 |
| 难度 | 中等 | 高级(但很香) |
? 单调队列小口诀
分组取模走队列,
队头最优直接追;
超数量就弹出去,
背包装满笑开怀!?
野牛程序员教少儿编程与信息学奥赛-微信|电话:15892516892

