有 N种物品和一个容量是 V 的背包。
第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤1000<N,V≤100
0<vi,wi,si≤1000<vi,wi,si≤100
输入样例
4 5
1 2 3
2 4 1
3 4 3
4 5 2
输出样例:
10
多重背包可以将每个物品的个数摊开,例如物品A有3件,把它看成三样 独立的东西,但是这样会产生很多重复计算,例如取第一件、第二件等价于取第二件、第三件等等等
所以还可以进一步优化 来减少重复计算。每个物品的个数可以化为二进制数,也就是说物品的个数 可以用多个2的次方组成
例如
14 =8 + 4 +2
11 = 8 +2 +1
那是不是说当物品个数为 n时,在可挑选物品中,添加多个可以组合成n以内的2的次方
例如该物品个数为14 =8 + 4 +2
所以在可挑选物品内添加 1个该物品、2个该物品、4个该物品、8个该物品。
这样就可以组合到14个物品内取任意个时的情况
但是,这样不仅可以组合到14个物品内的任意个,还可以组合到15个物品的情况,
所以我们进行分组时,要达到只能组合到不大于n的正数
所以以上例子可化为
14 =1+2+4+7
11 =1 + 2 + 4 +4
n = 2^{1} +2^{2}.......+2^{m}+剩余的数
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int n,m,V,W,s,a[100000]={0},v[100000]={0},w[100000],cut=0;// cut记录为当前物品序列(第几个)
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>V>>W>>s;
int p=1; //p为记录取几个当前物体作为一个独立的物体
while(s>p){
s-=p;
v[++cut]=p*V;
w[cut]=p*W;
p<<=1;
}
v[++cut]=s*V;
w[cut]=s*W;
}
for(int i=1;i<=cut;i++){ //01背包
for(int j=m;j;j--){
if(v[i]<=j)a[j]=max(a[j],a[j-v[i]]+w[i]);
else break;
}
}
cout<<a[m]<<endl;
return 0;
}