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 ", dp[M] ); return 0; }