hihocoder-Week195-奖券兑换

hihocoder-Week195-奖券兑换

 

时间限制:20000ms
单点时限:1000ms
内存限制:256MB

描述

小Hi在游乐园中获得了M张奖券,这些奖券可以用来兑换奖品。

可供兑换的奖品一共有N件。第i件奖品需要Wi张奖券才能兑换到,其价值是Pi。  

小Hi使用不超过M张奖券所能兑换到的最大奖品总价值是多少?

输入

第一行两个整数N,M。  

接下来N行,每行两个整数Wi,Pi。  

对于 50%的数据: 1≤N,M≤1000  

对于 100%的数据: 1≤N,M≤105,1≤Pi,Wi≤10。  

输出

一行一个整数,表示最大的价值。

样例输入
3 10  
2 3  
8 8   
10 10
样例输出
11 

 

题解:

  多重背包转化为01背包。可以使用二进制编码法则。将一个较大的数字,拆成C=1+2+4+8+...+2^K+R, 其中R < 2^(K+1) 的组合。

 

参考来源: http://hihocoder.com/discuss/question/5199

 

 

 

#include <cstdio> 
#include <cstring> 
#include <cstdlib> 
const int MAXN = 30 * 10 * 10; 

#define max(a, b) (a)>(b)?(a):(b) 

int M, N, W[MAXN], P[MAXN], mp[11][11], dp[MAXN*MAXN];  

int main()
{

	int p, w, tk; 

	scanf("%d %d", &N, &M); 
	memset( mp, 0, sizeof(mp) ); 
	
	for(int i=0; i < N; ++i )
	{
		scanf("%d %d", &w, &p);  
		mp[ w ][ p ] += 1; 
	}

	tk = 0; 
	for(int i=1; i<=10; ++i ) {
		for(int j = 1; j <= 10; ++j ) {
			if( mp[i][j] > 0 ) {
				W[ tk ] = i; 
				P[ tk ] = j;  
				++tk; 
				int cur = 1, k = mp[i][j] , cur_bit = 2; 
				while( cur + cur_bit <= k) {
					W[ tk ] = cur_bit * i; 
					P[ tk ] = cur_bit * j; 
					++tk; 
					cur += cur_bit; 
					cur_bit *= 2; 
				} 
				if( k > cur){
					W[ tk ] = ( k - cur ) * i; 
					P[ tk ] = ( k - cur ) * j; 
					++tk; 
				}
			} 
		} 
	}  

	memset( dp, 0, sizeof(dp) ); 
	for(int i=0; i<tk; ++i){
		for(int j=M; j>=W[i]; --j){
			dp[j] = max(dp[j], dp[j-W[i]] + P[i]); 
		}
	}
	printf("%d\n", dp[M] ); 

	return 0; 
}

  

 

posted @ 2018-03-30 09:54  zhang--yd  阅读(354)  评论(0编辑  收藏  举报