多重背包模板题,数据范围很小(N,V,s≤100),直接三重循环 DP,每个物品枚举选取件数即可。
OJ: luogu
题目 ID: U661992
难度:普及-
标签:动态规划多重背包背包
创建: 2026-08-08 23:11
更新: 2026-10-07 12:15
前置题目
roj 1294Charm BraceletB 的多重背包正解(main.cpp 第 21 行 for (int c = V; c >= 0; --c) 内套 k 循环)原样复用 A 教的『倒序枚举容量保证每件物品至多选一次』这一步,只把每件物品换成展平后的 s_i 个 01 副本并在内层叠加件数枚举,B 文中也明说与标准 01 背包的倒序要求完全一样。luogu U661988疯狂的背包问题(4) - 完全背包问题A 讲清的「倒序保证每件物品只用一次」被 B 直接当作展平后 01 物品的枚举方向依据,B 只是在同一 dp[c] 转移上内层叠加件数枚举luogu U661986疯狂的背包问题(1) - 01背包问题B 把每种物品的 s_i 件展平成多个 01 物品后,仍沿用 A 教的『容量倒序枚举保证每件物品只选一次』(main.cpp 第 21 行 for (int c = V; c >= 0; --c)),只是在倒序容量循环内层再枚举选取件数 k,属于在 01 背包模板上叠加一层枚举。
题意
有
思路
一句话本质:把每种物品的
最直接的做法是什么?
对每种物品枚举选取件数 brute.py 正是这样做的——DFS 枚举每种物品选几个,复杂度
既然选
可以。因为每件物品之间没有依赖关系——选第
这就得到了三重循环:
- 外层遍历每种物品
- 中层容量
从 倒序到 (01 背包要求倒序,防止同一轮中重复选取同一物品的多个"展平"副本) - 内层枚举选取件数
,更新
为什么容量循环必须倒序?
这和标准 01 背包完全一样。如果正序,已经更新过的
代码
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* 多重背包问题 I — N≤100 V≤100 s_i≤100,直接三重循环DP
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 105;
int n, V;
int dp[maxn];
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> V;
for (int i = 1; i <= n; ++i) {
int v, w, s;
cin >> v >> w >> s;
for (int c = V; c >= 0; --c)
for (int k = 1; k <= s && k * v <= c; ++k)
dp[c] = max(dp[c], dp[c - k * v] + k * w);
}
cout << dp[V] << '\n';
return 0;
}复杂度
- 时间:
,最坏 ,轻松通过。 - 空间:
,滚动数组。
总结
多重背包最朴素的做法就是把每个物品拆成