题意:给定一个数P,要求用四种币值为1,5,10,25的硬币拼成P,并且硬币数要最多。
分析:这是一个多重背包问题,但是要转换一下思路,现在要求硬币数量最多,那么P是背包容量,硬币面值是cost,硬币数量是weight。多重背包问题加上used数组可以转换为完全背包问题,这样可以减小复杂度。还有就是要记录各种面值的硬币使用了多少次,这就需要记录路径。
代码:
#include <iostream>
using namespace std;
#define INIT -99999
int P;
int dp[10001];
int used[10001];//使用used数组来标记used[j]达到金额j的时候,所使用的第i种钞票的个数
int path[10001];
int cost[5] = {0,1,5,10,25};
int cnt[26];
int main(int argc, char **argv)
{
while (scanf("%d%d%d%d%d",&P,&cnt[1],&cnt[2],&cnt[3],&cnt[4])!=EOF &&
P|cnt[1]|cnt[2]|cnt[3]|cnt[4]!=0) {
for(int i=1; i<=10001; ++i) {
dp[i] = INIT;
}
dp[0] = 0;
memset(path,0,sizeof(path));
path[0] = -1;
for (int i=1; i<=4; ++i) {
memset(used,0,sizeof(used));
for (int j=cost[i]; j<=P; ++j) {
if ( dp[j-cost[i]]!=INIT && dp[j]<dp[j-cost[i]]+1
&& used[j-cost[i]]+1<=cnt[i]) {
dp[j] = dp[j-cost[i]]+1;
used[j] = used[j-cost[i]] + 1;
path[j] = j - cost[i];
}
}
}
if (dp[P] != INIT) {
memset(cnt,0,sizeof(cnt));
while (path[P] != -1) {
cnt[P-path[P]]++;
P = path[P];
}
printf("Throw in %d cents, %d nickels, %d dimes, and %d quarters.\n",cnt[1],cnt[5],cnt[10],cnt[25]);
}
else printf("Charlie cannot buy coffee.\n");
}
system("pause");
return 0;
}
94MS过~