典型多重背包,和经典问题的不同点在于:
经典问题基本上都是问最少用多少钞票(最多用多少钞票)可以兑换出来
本题问的是用这些钞票在不超过取款金额的条件下最多可以取出多少现金
用状态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;
}

本文介绍了一种解决典型多重背包问题的方法,通过动态规划找出在不超过取款金额限制下能够取出的最大现金值。代码实现中使用了零一背包、完全背包及多重背包等算法,并详细展示了如何针对不同情况选择合适的方法。
922

被折叠的 条评论
为什么被折叠?



