Codevs 3269 混合背包
3269 混合背包
时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond
题目描述 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
1 // 混合背包板子 我的哥 全TLE~~~~~~~~ 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 using namespace std; 6 #define N 210 7 #define V 200010 8 int n,v,f[V],wi[N],mi[N],vi[N]; 9 int main() 10 { 11 scanf("%d%d",&n,&v); 12 for(int i=1;i<=n;i++) 13 { 14 scanf("%d%d%d",&vi[i],&wi[i],&mi[i]); 15 if(mi[i]==-1) mi[i]=v/vi[i]; 16 } 17 for(int i=1;i<=n;i++) 18 { 19 for(int k=1;k<=mi[i];k++) 20 { 21 for(int j=v;j>=vi[i];j--) 22 f[j]=max(f[j],f[j-vi[i]]+wi[i]); 23 } 24 } 25 printf("%d",f[v]); 26 return 0; 27 }
AC代码:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 #define N 210 6 #define V 200010 7 int n,v,f[V],wi[N],mi[N],vi[N]; 8 int main() 9 { 10 scanf("%d%d",&n,&v); 11 for(int i=1;i<=n;i++) 12 { 13 scanf("%d%d%d",&vi[i],&wi[i],&mi[i]); 14 if(mi[i]==-1) mi[i]=v/vi[i]; 15 } 16 for(int i=1;i<=n;i++) 17 { 18 int x=mi[i]; 19 for(int k=1;k<=x;k<<=1)//二分制优化 20 { 21 for (int j=v;j>=vi[i]*k;j--) 22 f[j]=max(f[j],f[j-vi[i]*k]+wi[i]*k); 23 x-=k; 24 } 25 if(x) 26 for (int j=v;j>=vi[i]*x;j--) 27 f[j]=max(f[j],f[j-vi[i]*x]+wi[i]*x); 28 } 29 printf("%d",f[v]); 30 return 0; 31 }
再次说明一点,我将可以去无数次的物品的次数换成了v/vi[i]次(即通过总背包体积来限制他,这样就可以省掉一步)。。。
二进制优化~~~依然的慢
待解救~~~~~~~
还有这题和队列有个毛关系~~