codevs 3269 混合背包 如题(二进制优化)
Posted lpl_bys
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了codevs 3269 混合背包 如题(二进制优化)相关的知识,希望对你有一定的参考价值。
3269 混合背包
背包体积为V ,给出N个物品,每个物品占用体积为Vi,价值为Wi,每个物品要么至多取1件,要么至多取mi件(mi > 1) , 要么数量无限 , 在所装物品总体积不超过V的前提下所装物品的价值的和的最大值是多少?
第一行两个数N,V,下面N行每行三个数Vi,Wi,Mi表示每个物品的体积,价值与数量,Mi=1表示至多取一件,Mi>1表示至多取Mi件,Mi=-1表示数量无限
1个数Ans表示所装物品价值的最大值
2 10
3 7 2
2 4 -1
22
对于100%的数据,V <= 200000 , N <= 200
------------------------------------------------------------------------------------------------------------------------
看题目就知道是混合背包模板题
这里的多重背包不能用三个for,即不能够直接把每件物品的数量展开变成01背包,会T,需要用二进制拆分优化
简单地讲一下自己对于二进制拆分的理解吧
用二进制拆分的方法,也是将多重背包转化为01背包,但我们不是一个一个地去枚一种物品的数量,而是把这个物品的数量按二进制拆分成几个数。例如物品的数量为7,体积为v,价值为w,则7的二进制为111,就可以把7拆成 001 010 100 ,即1 2 4,这样就能把这中数量为7的物品拆分成3种数量为1的物品,分别为 v1=1*v,w1=1*w ; v2=2*v,w2=2*w ; v3=4*v,w3=4*w。
为什么能这样拆呢?
因为这样拆之后的选择可以囊括所有组合
还是以上面的例子
把7(111)拆成001 010 100之后,这三个数可以组合成任意小于等于7的自然数。
详细看代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #define maxn 233333 5 using namespace std; 6 int read(); 7 void zeropack(int,int); 8 void compack(int,int); 9 void multpack(int,int,int); 10 int n,V,dp[maxn]; 11 int main(){ 12 n=read(),V=read(); 13 for(int i=1;i<=n;i++){ 14 int v=read(),w=read(),num=read(); 15 if(num==1) zeropack(v,w); 16 else if(num==-1) compack(v,w); 17 else multpack(v,w,num); 18 } 19 printf("%d",dp[V]); 20 return 0; 21 } 22 void zeropack(int v,int w){ 23 for(int i=V;i>=v;i--) 24 dp[i]=max(dp[i],dp[i-v]+w); 25 } 26 void compack(int v,int w){ 27 for(int i=v;i<=V;i++) 28 dp[i]=max(dp[i],dp[i-v]+w); 29 } 30 void multpack(int v,int w,int num){ 31 if(num*v>=V){ 32 compack(v,w); 33 return; 34 } 35 int k=1; 36 while(k<num){ 37 zeropack(v*k,w*k); 38 num-=k; 39 k<<=1; 40 } 41 if(num>0) zeropack(num*v,num*w); 42 } 43 int read(){ 44 int ans=0,f=1;char c=getchar(); 45 while(‘0‘>c||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();} 46 while(‘0‘<=c&&c<=‘9‘)ans=ans*10+c-48,c=getchar();return ans*f; 47 }
以上是关于codevs 3269 混合背包 如题(二进制优化)的主要内容,如果未能解决你的问题,请参考以下文章