題意:給定一個數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過~