BZOJ1190: [HNOI2007]夢幻島寶珠

【傳送門:BZOJ1190


簡要題意:

  給出n個物品以及揹包的總容量W,每一個物品有一個價值v和體積w,保證w=a*2b(a<=10且b<=30)php

  求出最大價值數組


題解:

  直接01揹包顯然爆炸
spa

  實際上咱們能夠將b相同的物品分紅一組,f[i][j]表示b=i的全部物品,組成j*2b爲整體積所能獲得的最大價值
code

  由於咱們能夠肯定j<=10*n=1000,因此能夠先分開各自01揹包blog

  而後將獲得的f數組再組合,這時f數組就是f[i][j]表示2^0到2^i組內,容量爲j*2^i+(w&((1<<i)-1))時的最大價值get

  由於後面的物品的總容量最多達到10*n,因此轉移的時候對10*m取一下min就好了string


參考代碼:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
int f[41][1100];
int main()
{
    int n,W,i,j,k,w,v,len,ww;
    while(1)
    {
        scanf("%d%d",&n,&W);
        if(n==-1&&W==-1) break;
        memset(f,0,sizeof(f));
        for(i=1;i<=n;++i)
        {
            scanf("%d%d",&w,&v);
            k=0;
            while(w%2==0) w=w/2,k++;
            for(j=10*n;j>=w;--j) f[k][j]=max(f[k][j-w]+v,f[k][j]);
        }
        len=0,ww=W;
        while(ww!=0) ww/=2,len++;
        len--;
        for(i=1;i<=len;++i)
        {
            for(j=10*n;j>=0;--j)
            {
                for(k=0;k<=j;++k)
                {
                    f[i][j]=max(f[i][j],f[i][j-k]+f[i-1][min(10*n,(k*2)+((W>>(i-1))&1))]);
                }
            }
        }
        printf("%d\n",f[len][1]);
    }
    return 0;
}
相關文章
相關標籤/搜索