原题:混合背包问题
在本题中 n ∈ [1, 1000], m ∈ [1, 2000], s ∈ [1, 2000]
若使用传统多重背包写法:
三重循环嵌套-时间复杂度为:
枚举n件物品 * 枚举背包体积v * 每件物品数s
时间复杂度 这显然是我们不可以接受的
但是每次第三层循环都要从把物品所有可能数量枚举一遍
或许我们可以考虑将件物品等效,使得的数量减少,且原本可以由s件物品选出的仍可以被表示出
我们考虑将s打包为 使得
则任意数 均可由a中数字组合得出
于是将其打包成物品集合
跑一遍01背包即可
//算法提高课背包dp
//混合背包化作多重背包
//11/26 10/13 TLE
//11/26 10/13 WA : 二进制优化
//11/26 Ac : 个数开到nlogn 即 N = log1e3 * 1e3 ~= 1e4
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1e4 + 10;
int n, m;
int f[N], v[N], w[N], s[N], cnt = 0;
int main(){
freopen("bag.in", "r", stdin);
freopen("bag.out", "w", stdout);
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++){
int W, V, S;
scanf("%d%d%d", &W, &V, &S);
if(S == -1)S = 1;
else if(S == 0)S = m / W;
int k = 1;
while(k <= S){
w[++cnt] = k * W;
v[cnt] = k * V;
S -= k;
k *= 2;
}
if(S){
w[++cnt] = S * W;
v[cnt] = S * V;
}
}
n = cnt;
for(int i = 1; i <= n; i ++){
for(int j = m; j >= w[i]; j --){
f[j] = max(f[j], f[j - w[i]] + v[i]);
}
}
printf("%d", f[m]);
return 0;
}