【BZOJ1190】梦幻岛宝珠(HNOI2007)-背包DP+思维

测试地址:梦幻岛宝珠
做法: 本题需要用到背包DP+思维。
这道题看上去是一个裸01背包,然而容量特别大,因此我们只能从其中唯一一个特殊条件入手: a ⋅ 2 b a\cdot 2^b a2b形式的重量。
我们考虑把这些物品分阶段来进行决策。我们首先对每个 b b b,求出重量表示为 a ⋅ 2 b a\cdot 2^b a2b的那些物品中,取重量为 k ⋅ 2 b k\cdot 2^b k2b的物品能得到的最大总价值 t o t v a l ( b , k ) totval(b,k) totval(b,k),这就是一个一般的01背包了,因为 a ≤ 10 , n ≤ 100 a\le 10,n\le 100 a10,n100,所以时间复杂度最多是 1 0 6 10^6 106的级别。接下来,我们从低位向高位DP,令 f ( i , j ) f(i,j) f(i,j)为取用 b ≤ i b\le i bi的物品,容量为 j ⋅ 2 i j\cdot 2^i j2i加上 W W W在第 i i i位以下的所有容量时所能得到的最大总价值。上面 W W W在第 i i i位以下的容量,就指的是它在第 i i i位以下的上界(用位运算解释就是 W &amp; ( ( 1 &lt; &lt; i ) − 1 ) W\&amp;((1&lt;&lt;i)-1) W&((1<<i)1))。在转移的时候,我们首先枚举当前的 j j j,然后看前一位有哪些可以转移到当前状态的状态。显然,由于要满足第 i i i位之前是上界的条件,第 i − 1 i-1 i1位应该和 W W W的第 i − 1 i-1 i1位相同,这才能转移。于是我们就写出来了一个状态转移的式子,就解决了这道题,时间复杂度虽然看上去有点大,但均摊下来还是跑得很快的。
以下是本人代码:

#include <bits/stdc++.h>
using namespace std;
int n,W,totw[35],f[35][2100],len;
vector<int> w[35],val[35];

int main()
{
	while(scanf("%d%d",&n,&W)&&n>=0&&W>=0)
	{
		len=0;
		for(int i=0;i<35;i++)
			w[i].clear(),val[i].clear();
		memset(totw,0,sizeof(totw));
		memset(f,0,sizeof(f));
		
		for(int i=1;i<=n;i++)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			int j=0;
			while(!(x&1)) {j++;x>>=1;}
			w[j].push_back(x);
			totw[j]+=x;
			val[j].push_back(y);
			len=max(len,j);
		}
		while(W>>len) len++;
		len--;
		
		for(int i=0;i<=len;i++)
			for(int j=0;j<(int)w[i].size();j++)
				for(int k=totw[i];k>=w[i][j];k--)
					f[i][k]=max(f[i][k],f[i][k-w[i][j]]+val[i][j]);
		
		for(int i=1;i<=len;i++)
		{
			totw[i]+=((totw[i-1]+1)>>1);
			for(int j=totw[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(totw[i-1],(k<<1)|((W>>(i-1))&1))]);
		}
		printf("%d\n",f[len][1]);
	}
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值