多重揹包之二進位制優化
阿新 • • 發佈:2018-12-16
分析
多重揹包,就是在0/1揹包的基礎上,固定每個物品選的上限(最多選多少個)
最簡單的方法就是直接拆分
將第i種物品看做獨立的ci個物品,轉化為0/1揹包即可
但這樣顯然不優,於是我們想到了二進位制
把物品的件數C 用分解成若干個件數的集合,這裡面數字可以組合成任意小於等於C的件數,而且不會重複,之所以叫二進位制分解,是因為這樣分解可以用數字的二進位制形式來解釋比如:7的二進位制 7 = 111 它可以分解成 001 010 100 這三個數可以組合成任意小於等於7 的數,而且每種組合都會得到不同的數15 = 1111 可分解成 0001 0010 0100 1000 四個數字 如果13 = 1101 則分解為 0001 0010 0100 0110 前三個數字可以組合成 7以內任意一個數,加上 0110 = 6 可以組合成任意一個大於6 小於13的數,雖然有重複但總是能把 13 以內所有的數都考慮到了,基於這種 思想去把多件物品轉換為,多種一件物品,就可用01 揹包求解了。
這道題顯然板題
程式碼
#include<bits/stdc++.h> #define in read() using namespace std; inline int read(){ char ch;int f=1,res=0; while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1; while(ch>='0'&&ch<='9'){ res=(res<<3)+(res<<1)+ch-'0'; ch=getchar(); } return f==1?res:-res; } int n,w,f[500009]; int val[500009],weight[500009],cnt=0; int main(){ n=in;w=in; int i,j,v,z,shu; for(i=1;i<=n;++i){ v=in;z=in;shu=in; for(j=1;j<=shu;j<<=1){//拆分 val[++cnt]=v*j; weight[cnt]=z*j; shu-=j; } if(shu){ val[++cnt]=shu*v; weight[cnt]=shu*z; } } for(i=1;i<=cnt;++i) for(j=w;j>=weight[i];--j) f[j]=max(f[j],f[j-weight[i]]+val[i]); int ans=-1; for(i=0;i<=w;++i) ans=max(ans,f[i]); cout<<ans; return 0; }