题目链接:https://hihocoder.com/problemset/problem/1364
#1364 : 奖券兑换
时间限制:
20000ms
单点时限:
1000ms
内存限制:
256MB
-
3 10 2 3 8 8 10 10
样例输出
-
11
描述
小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。
输出
一行一个整数,表示最大的价值。
解析:按01背包10^10, 必然超时, 由于所有情况10*10,咱们可以把01背包转换成多重背包
代码:
#include<bits/stdc++.h>
#define N 100009
using namespace std;
int num[20][20], dp[N];
int n, m;
void Zero_(int w, int v)
{
for(int i = m; i >= w; i--)
dp[i] = max(dp[i], dp[i - w] + v);
}
void Com_(int w, int v)
{
for(int i = w; i <= m; i++)
dp[i] = max(dp[i], dp[i - w] + v);
}
void M_(int w, int v, int cnt)
{
if(m <= w*cnt) Com_(w, v);
else
{
for(int i = 1; i <= cnt; cnt -= i, i <<= 1)
Zero_(w*i, v*i);
if(cnt) Zero_(w*cnt, v*cnt);
}
}
int main()
{
int w, v;
memset(num, 0, sizeof(num));
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
{
scanf("%d%d", &w, &v);
num[w][v]++;
}
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= 10; i++)
{
for(int j = 1; j <= 10; j++)
M_(i, j, num[i][j]);
}
printf("%d\n", dp[m]);
return 0;
}