From 90c1eb05d0b765c91f6e3646dd492890dbe6f840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B5=B7?= <10402852@qq.com> Date: Tue, 12 Mar 2024 10:07:40 +0800 Subject: [PATCH] 'commit' --- TangDou/AcWing/BeiBao/背包问题专题.md | 47 +++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/TangDou/AcWing/BeiBao/背包问题专题.md b/TangDou/AcWing/BeiBao/背包问题专题.md index b6b4854..53bf3d6 100644 --- a/TangDou/AcWing/BeiBao/背包问题专题.md +++ b/TangDou/AcWing/BeiBao/背包问题专题.md @@ -418,4 +418,51 @@ int main() { printf("%d\n", f[m]); return 0; } +``` + +**[$AcWing$ $5$. 多重背包问题 II](https://www.acwing.com/problem/content/description/5/)** + +```cpp {.line-numbers} +#include +using namespace std; + +const int N = 1010; // 个数上限 +const int M = 2010; // 体积上限 +int n, m, idx; +int f[M]; + +/* +Q:为什么是N*12? +A:本题中v_i<=2000,因为c数组是装的打包后的物品集合,每类物品按二进制思想,2000最多可以打log2(2000)+1个包,即 10.96578+1=12个足够, +同时,共N类物品,所以最大值是N*12。 + +如果题目要求v_i<=INT_MAX,那么就是log2(INT_MAX)=31,开31个足够,因为31是准确的数字,不需要再上取整。 +为保险起见,可以不用计算数组上限,直接N*32搞定! +*/ +struct Node { + int w, v; +} c[N * 12]; + +int main() { + cin >> n >> m; + + // 多重背包的经典二进制打包办法 + for (int i = 1; i <= n; i++) { + int v, w, s; + cin >> v >> w >> s; + for (int j = 1; j <= s; j *= 2) { // 1,2,4,8,16,32,64,128,...打包 + c[++idx] = {j * w, j * v}; + s -= j; + } + // 不够下一个2^n时,独立成包 + if (s) c[++idx] = {s * w, s * v}; + } + // 按01背包跑 + for (int i = 1; i <= idx; i++) + for (int j = m; j >= c[i].v; j--) // 倒序 + f[j] = max(f[j], f[j - c[i].v] + c[i].w); + // 输出 + printf("%d\n", f[m]); + return 0; +} ``` \ No newline at end of file