AcWing 5. 多重背包问题 II
原题链接
中等
作者:
rushhhhh
,
2021-02-15 17:16:12
,
所有人可见
,
阅读 230
#include <iostream>
using namespace std;
// 把多重背包问题转化为01背包问题
// 如果直接转化,就是把每个物品变成s个01背包的物品,则共有2000*1000个物品
// 这种01背包的时间复杂度是2000*1000*2000,仍然会超时
// 因此要通过二进制来优化01背包的物品数
// 例如,要选择10个物品,原本直接转化需要循环10次,因为是i++
// 现在,通过二进制,直接选1、2、4、8(3),仅需4次操作
// 时间复杂度由1000*2000*2000变成1000*2000*log2000,于是N(物品数量)取1000*log2000≈22000
// O(N^3) -> O(N^2 * logN)
const int N = 22000;
int f[N];
int v[N], w[N];
int n, m;
// 每个s[i]都能用1,2,4,8...来表示
// 所以每次取k个都可以表示成每次是否取k*w[i]的01背包问题
int main()
{
cin >> n >> m;
int cnt = 0;
for(int i=1; i<=n; i++)
{
int a, b, s;
cin >> a >> b >> s;
int k = 1;
while(k <= s)
{
cnt++;
v[cnt] = a*k;
w[cnt] = b*k;
s -= k;
k *= 2;
}
if(s > 0)
{
cnt++;
v[cnt] = a*s;
w[cnt] = b*s;
}
}
// 至此,转化成了01背包问题
// 问题规模变大了,但是循环层数少了一层
n = cnt;
for(int i=1; i<=n; i++)
for(int j=m; j>=v[i]; j--)
f[j] = max(f[j], f[j-v[i]]+w[i]);
cout << f[m];
return 0;
}