1. 程式人生 > >【HNOI 2007】夢幻島寶珠

【HNOI 2007】夢幻島寶珠

題目描述

給你 N(N100)N(N\le 100) 顆寶石,每顆寶石都有重量和價值。要你從這些寶石中選取一些寶石,保證總重量不超過 W(W230)W(W\le 2^{30}),輸出最大的總價值。保證每顆寶石的重量符合 a×2b(a10,b30)a\times 2^b(a\le 10,b\le30)

演算法分析

f[i][j]f[i][j] 表示揹包容量為 j×2i+W&((1<<i)1)j\times 2^i+W\&((1<<i)-1)

+W&((1<<i)1) 時的最大總價值,ii 相同時的轉移等同 0/1 揹包,ii 不同時有 f[i][j]=min{f[i][j],f[i][k]+f[i1][2×k+(W&gt;&gt;(i1)&amp;1)]}f[i][j]=min\{f[i][j],f[i][k]+f[i-1][2\times k+(W&gt;&gt;(i-1)\&amp;1)]\}我好菜啊

程式碼實現

#include
<cstdio>
#include <cstring> #include <algorithm> #define UPD(x,y) x=std::max(x,y) #define Min(x,y) std::min(x,y) int n,w,f[35][1005]; int main() { while(scanf("%d%d",&n,&w)==2&&((~n)||(~n))) { memset(f,0,sizeof(f)); for(int i=0;i<n;++i) { int a,b=0,v; scanf
("%d%d",&a,&v); while(!(a&1)) {++b;a>>=1;} for(int j=1000;j>=a;--j) UPD(f[b][j],f[b][j-a]+v); } int top=-1;for(int i=w;i;i>>=1) ++top; for(int i=1;i<=top;++i) { for(int j=1000;j>=0;--j) for(int k=0;k<=j;++k) UPD(f[i][j],f[i][j-k]+f[i-1][Min(1000,(k<<1)|(w>>(i-1)&1))]); } printf("%d\n",f[top][1]); } return 0; }