【HNOI 2007】梦幻岛宝珠

题目描述

给你 N ( N ≤ 100 ) N(N\le 100) N(N100) 颗宝石,每颗宝石都有重量和价值。要你从这些宝石中选取一些宝石,保证总重量不超过 W ( W ≤ 2 30 ) W(W\le 2^{30}) W(W230),输出最大的总价值。保证每颗宝石的重量符合 a × 2 b ( a ≤ 10 , b ≤ 30 ) a\times 2^b(a\le 10,b\le30) a×2b(a10,b30)

算法分析

f [ i ] [ j ] f[i][j] f[i][j] 表示背包容量为 j × 2 i + W &amp; ( ( 1 &lt; &lt; i ) − 1 ) j\times 2^i+W\&amp;((1&lt;&lt;i)-1) j×2i+W&((1<<i)1) 时的最大总价值, i i i 相同时的转移等同 0/1 背包, i i i 不同时有 f [ i ] [ j ] = m i n { f [ i ] [ j ] , f [ i ] [ k ] + f [ i − 1 ] [ 2 × k + ( W &gt; &gt; ( i − 1 ) &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)]\} f[i][j]=min{f[i][j],f[i][k]+f[i1][2×k+(W>>(i1)&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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值