洛谷 1776 宝物筛选 多重背包+二进制拆分
Posted Driver_Lao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 1776 宝物筛选 多重背包+二进制拆分相关的知识,希望对你有一定的参考价值。
【题解】
显然是个多重背包。但直接写背包会超时。所以我们试着优化。
怎么优化?我们发现,每个物品的个数$ai$可以拆分成几个数的和,用这些数中的某几个之和可以表示出$1$到$ai$的所有整数,并且不会超过$ai$
这样我们可以把ai个相同的物品拆分成若干个互相独立的物品,然后跑01背包。
那么如何对$ai$进行拆分?拆分出来的数就是相加起来不超过$ai$的2的$i$次幂以及$ai$减去2的$i$次幂之和的结果。
例如我们可以把19拆分成$1,2,4,8,3$
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 int n,w,f[200010]; 5 inline int read(){ 6 int f=1,k=0; char c=getchar(); 7 while(c<\'0\'||c>\'9\')c==\'-\'&&(f=-1),c=getchar(); 8 while(\'0\'<=c&&c<=\'9\')k=k*10+c-\'0\',c=getchar(); 9 return k*f; 10 } 11 int main(){ 12 n=read(); w=read(); 13 while(n--){ 14 int vi=read(),wi=read(),ai=read(),i; 15 for(i=0;((1<<(i+1))-1)<=ai;i++){ 16 for(int j=w;j>=(wi<<i);j--) 17 f[j]=max(f[j-(wi<<i)]+(vi<<i),f[j]); 18 } 19 int tmp=ai-(1<<i)+1; 20 vi=vi*tmp; wi=wi*tmp; 21 for(int j=w;j>=wi;j--) f[j]=max(f[j-wi]+vi,f[j]); 22 } 23 printf("%d\\n",f[w]); 24 return 0; 25 }
以上是关于洛谷 1776 宝物筛选 多重背包+二进制拆分的主要内容,如果未能解决你的问题,请参考以下文章