|
|
|
@ -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 <bits/stdc++.h>
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
```
|