您的位置:首页 > 其它

1190: [HNOI2007]梦幻岛宝珠

2017-11-01 09:57 316 查看

这是一道很好的DP哦

非常值得去做

大家都叫它分层背包(其实很好理解啦)

就是先按照二进制位分层,然后先在层内简单背包

f [i] [j] 表示 容量第 i 个二进制位为 j 的最大价值

换句话说就是 容量为 j*2^i 的最大价值

然后就是把各个层合并

这个时候 f [i] [j] 表示 容量为 j*2^i+(W第i-1位之前) 的最大价值

这里要注意: 不是j*2^i还要加上W本身前i-1位

然后转移方程显然

最后输出 f [32] [0] 就好了

#include<bits/stdc++.h>
using namespace std;
int n,W,x,pos;
int w[33][105],v[33][105],sum[33],f[33][500],cnt[33];
int main()
{
while(~scanf("%d%d",&n,&W)&&n!=-1)
{
memset(w,0,sizeof(w));
memset(v,0,sizeof(v));
memset(sum,0,sizeof(sum));
memset(cnt,0,sizeof(cnt));
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
pos=0;
while(x%2==0)
pos++,x>>=1;
w[pos][++cnt[pos]]=x;
sum[pos]+=x;
4000
scanf("%d",&v[pos][cnt[pos]]);
}
for(int i=0;i<=31;i++)
for(int j=1;j<=cnt[i];j++)
for(int k=sum[i];k>=w[i][j];k--)
f[i][k]=max(f[i][k],f[i][k-w[i][j]]+v[i][j]);

for(int i=1;i<=31;i++)
{
sum[i]+=(sum[i-1]+1)>>1;
for(int j=sum[i];j>=0;j--)
for(int k=0;k<=j;k++)
f[i][j]=max(f[i][j],f[i][j-k]+f[i-1][min(sum[i-1],(k<<1)|(W>>(i-1))&1)]);
}
printf("%d\n",f[31][0]);
}
}


心得:

1.多做DP
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: