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
相关文章推荐
- BZOJ 1190 [HNOI2007]梦幻岛宝珠
- 【BZOJ1190】[HNOI2007]梦幻岛宝珠 分层背包DP
- 【bzoj1190】[HNOI2007]梦幻岛宝珠 分层背包dp
- BZOJ 1190 HNOI2007 梦幻岛宝珠 动态规划
- [BZOJ 1190][HNOI2007]梦幻岛宝珠
- 1190: [HNOI2007]梦幻岛宝珠 - BZOJ
- bzoj1190 [HNOI2007]梦幻岛宝珠 ( 二进制分组优化背包DP)
- [DP]BZOJ 1190——[HNOI2007]梦幻岛宝珠 动态规划]
- [bzoj1190][HNOI2007]梦幻岛宝珠 分组背包
- BZOJ 1190: [HNOI2007]梦幻岛宝珠
- [数位DP] BZOJ1190. [HNOI2007]梦幻岛宝珠
- BZOJ 1190: [HNOI2007]梦幻岛宝珠 背包DP
- 分层背包 [HNOI2007]梦幻岛宝珠
- 题解 P3188 【[HNOI2007]梦幻岛宝珠】 DP
- BZOJ 1190: [HNOI2007]梦幻岛宝珠
- BZOJ 1190 梦幻岛宝珠
- [DP 背包] BZOJ 1190 [HNOI2007]梦幻岛宝珠
- 【bzoj1190】[HNOI2007]梦幻岛宝珠 分层背包dp
- BZOJ 1190 梦幻岛宝珠 [01背包][二进制优化]
- bzoj1190 梦幻岛宝珠 动态规划