您的位置:首页 > 其它

BZOJ 1190 [HNOI2007]梦幻岛宝珠

2016-11-09 21:30 344 查看
分组背包DP

看到w很大,不能直接做。但是w=a*2^b,且a,b都不大,就是让我们用2^a分组。

分组之后先组内DP求出f[i][j]表示仅在2^i组内,

容量为2^i*j时的最大价值。

然后组间DP再求出一个f[i][j]表示2^0~2^i组内,

容量为 j*2^i+(w&((1<< i)-1)) 时的最大价值

方程:cmax(f[i][j], f[i][k] + f[i-1][((j-k)<<1)+((W>>(i-1))&1)])

注意DP的时候第二维要从大到小- -

#include<cstdio>
#include<cstring>
#include<algorithm>
#define B 32
#define V 1005
#define cmax(u,v) (u)<(v)?(u)=(v):0
using namespace std;
namespace ziqian
{
int f[B][V];
void main()
{
int n, W, ans;
while(scanf("%d%d",&n,&W), n!=-1)
{
memset(f,0,sizeof(f));
ans = 0;
for(int i = 1, v, a, b; i <= n; i++)
{
scanf("%d%d",&b,&v);
a=0;
while((b&1)==0)
{
a++;
b>>=1;
}
for(int j = min(1000, W>>a); j >= b; j--)
{
cmax(f[a][j], f[a][j-b] + v);
cmax(ans, f[a][j]);
}
}
for(int i = 1; i < B && (1<<i) < W; i++)
{
for(int j = min(1000, W>>i); j >= 0; j--)
{
for(int k = j; k >= 0; k--)
{
cmax(f[i][j], f[i][k] + f[i-1][min( ((j-k)<<1)+((W>>(i-1))&1), 1000)]);
}
cmax(ans, f[i][j]);
}
}
printf("%d\n",ans);
}
}
}
int main()
{
ziqian::main();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: