典型多重背包,和经典问题的不同点在于:
经典问题基本上都是问最少用多少钞票(最多用多少钞票)可以兑换出来
本题问的是用这些钞票在不超过取款金额的条件下最多可以取出多少现金
用状态dp[i] = 1表示在当前条件下可以取出数量为i的现金,dp[i] = 0表示不能取出,dp过程中即可找到可取现金的最大值
#include <stdio.h>
#include <string.h>
#define max(a,b) ((a) > (b) ? (a) : (b))
int money, cash;
int N, amount[10 + 1], value[10 + 1];
char dp[100000 + 1];
void zeroOnePack(int v)
{
int i = money;
for(; i >= v; --i)
if(dp[i] |= dp[i - v]) cash = max(cash, i);
}
void completePack(int v)
{
int i = v;
for(; i <= money; ++i)
if(dp[i] |= dp[i - v]) cash = max(cash, i);
}
void multiPack(int v, int c)
{
if(v * c >= money){
completePack(v);
return;
}
int k = 1;
for(; k < c; k <<= 1){
zeroOnePack(v * k);
c -= k;
}
zeroOnePack(v * c);
}
int main()
{
int i, total;
while(scanf("%d %d", &money, &N) == 2){
total = 0;
/* input */
for(i = 0; i < N; ++i){
scanf("%d %d", &amount[i], &value[i]);
total += amount[i] * value[i];
}
/* judge */
if(money == 0 || N == 0) puts("0");
else if(total <= money) printf("%d\n", total);
else{
/* initialize */
memset(dp, 0, money + 1);
dp[0] = 1;
cash = 0;
/* multi-pack*/
for(i = 0; i < N; ++i){
if(amount[i]) multiPack(value[i], amount[i]);
}
/* print result */
printf("%d\n", cash);
}
}
return 0;
}