硬幣找零
- 描述
-
在現實生活中,我們經常遇到硬幣找零的問題,例如,在發工資時,財務人員就需要計算最少的找零硬幣數,以便他們能從銀行拿回最少的硬幣數,並保證能用這些硬幣發工資。我們應該注意到,人民幣的硬幣系統是 100,50,20,10,5,2,1,0.5,0.2,0.1,0.05,0.02,0.01 元,採用這些硬幣我們可以對任何一個工資數用貪心算法求出其最少硬幣數。但不幸的是: 我們可能沒有這樣一種好的硬幣系統, 因此用貪心算法不能求出最少的硬幣數,甚至有些金錢總數還不能用這些硬幣找零。例如,如果硬幣系統是 40,30,25 元,那麼 37元就不能用這些硬幣找零;95 元的最少找零硬幣數是 3。又如,硬幣系統是 10,7,5,1元,那麼 12 元用貪心法得到的硬幣數爲 3,而最少硬幣數是 2。你的任務就是:對於任意的硬幣系統和一個金錢數,請你編程求出最少的找零硬幣數;如果不能用這些硬幣找零,請給出一種找零方法,使剩下的錢最少。
- 輸入
- 輸入數據:
第 1 行,爲 N 和 T,其中 1≤N≤50 爲硬幣系統中不同硬幣數;1≤T≤100000 爲需要用硬幣找零的總數。
第 2 行爲 N 個數值不大於 65535 的正整數,它們是硬幣系統中各硬幣的面值。
當n,t同時爲0時結束。 - 輸出
- 輸出數據:
如 T 能被硬幣系統中的硬幣找零,請輸出最少的找零硬幣數。
如 T 不能被硬幣系統中的硬幣找零,請輸出剩下錢數最少的找零方案中的最少硬幣數。 - 樣例輸入
-
4 12 10 7 5 1
- 樣例輸出
-
2
解題思路:
這個問題類似於01揹包! 不同的是每種物品有無限件。我們只需要把01揹包的v的次序改一下就可以。想一想問什麼01揹包要從按v遞減的順序開始循環。
代碼:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<algorithm>
#define INF 0x1f1f1f1f
using namespace std;
int main()
{
int i, j, n, t;
int dp[100010], v[55];
while(scanf("%d%d",&n,&t) &&(n + t))
{
for(i = 0; i < n; i++)
scanf("%d",&v[i]);
memset(dp,INF,sizeof(dp));//因爲要求最小的所以初值爲最大值!
printf("%d\n",dp[0]);
dp[0] = 0;
for(j = 0; j < n; j++)
{
for(i = v[j]; i <= t; i++)
{
dp[i] = min(dp[i], dp[i - v[j]] + 1);//
}
}
for(i = t; i >= 0; i--)
{
if(dp[i] != INF)
{
printf("%d\n",dp[i]);
break;
}
}
}
return 0;
}