题目描述 Description
背包体积为V ,给出N个物品,每个物品占用体积为Vi,价值为Wi,每个物品要么至多取1件,要么至多取mi件(mi > 1) , 要么数量无限 , 在所装物品总体积不超过V的前提下所装物品的价值的和的最大值是多少?
输入描述 Input Description
第一行两个数N,V,下面N行每行三个数Vi,Wi,Mi表示每个物品的体积,价值与数量,Mi=1表示至多取一件,Mi>1表示至多取Mi件,Mi=-1表示数量无限
输出描述 Output Description
1个数Ans表示所装物品价值的最大值
样例输入 Sample Input
2 10
3 7 2
2 4 -1
样例输出 Sample Output
22
数据范围及提示 Data Size & Hint
对于100%的数据,V <= 200000 , N <= 200
题解:01+多重+完全背包。多重背包必须加二分制优化。不然全部超时。
二分制优化:将第i件物品分为若干件物品,其中每件物品都有一个系数,这件物品的费用和价值均是原来的费用和价值乘以这个系数,是这些系数分别为1,2,4,...2^(k-1),n[i]-2^k+1,且k是满足n[i]-2^k+1>0的最大整数。而这些数字可以组合成1~n[i]内的所有数字。
例如12,可将其分为1,2,4,5.
#include<cstdio> #include<iostream> #define N 210 #define V 200100 using namespace std; int n,v; int vi[N],wi[N],mi[N],f[V]={0}; int main() { scanf("%d%d",&n,&v); for (int i=1;i<=n;i++) scanf("%d%d%d",&vi[i],&wi[i],&mi[i]); for (int i=1;i<=n;i++) { if (mi[i]==-1)//完全背包 for (int j=vi[i];j<=v;j++) f[j]=max(f[j],f[j-vi[i]]+wi[i]); else { for (int k=1;k<=mi[i];k++)//01和多重背包 for (int j=v;j>=vi[i];j--) f[j]=max(f[j],f[j-vi[i]]+wi[i]); } } cout<<f[v]<<endl; return 0; }
#include<cstdio> #include<iostream> #define N 210 #define V 200100 using namespace std; int n,v; int vi[N],wi[N],mi[N],f[V]={0}; int main() { scanf("%d%d",&n,&v); for (int i=1;i<=n;i++) scanf("%d%d%d",&vi[i],&wi[i],&mi[i]); for (int i=1;i<=n;i++) { if (mi[i]==-1) for (int j=vi[i];j<=v;j++) f[j]=max(f[j],f[j-vi[i]]+wi[i]); else { int x=mi[i]; for (int k=1;k<=x;k<<=1)//二分制优化 { for (int j=v;j>=vi[i]*k;j--) f[j]=max(f[j],f[j-vi[i]*k]+wi[i]*k); x-=k; } if (x) for (int j=v;j>=vi[i]*x;j--) f[j]=max(f[j],f[j-vi[i]*x]+wi[i]*x); } } cout<<f[v]<<endl; return 0; }