題目來源:NYOJ995
問題描述:
在現實生活中,我們經常遇到硬幣找零的問題,例如,在發工資時,財務人員就需要計算最少的找零硬幣數,以便他們能從銀行拿回最少的硬幣數,並保證能用這些硬幣發工資。
輸入:
多組測試數據,每組如下:
第 1 行,為 N 和 T,其中 1≤N≤50 為硬幣系統中不同硬幣數;1≤T≤100000 為需要用硬幣找零的總數。
第 2 行為 N 個數值不大於 65535 的正整數,它們是硬幣系統中各硬幣的面值。
當N,T同時為0時結束。
輸出:
如 T 能被硬幣系統中的硬幣找零,請輸出最少的找零硬幣數。
如 T 不能被硬幣系統中的硬幣找零,請輸出剩下錢數最少的找零方案中的最少硬幣數。
分析:
假設N種硬幣面值按升序排序后,依次為v1, v2, ……vn,用f(t)表示找零總數為t時需要的最少硬幣數,當f(t) = 0時,表示不能用這些硬幣組合出t。
對於找零總數T,可以分解成 T = (T - vi) + vi, (其中i = 1 ……n)。因此,可以得到遞推關系式:
f(T) = min( f(T - vi)) + 1, (其中i = 1 …… n)
初始條件:
f(vi) = 1 (其中i =1 ……n),
當t < v1時,f(t) = 0;
代碼:
1、遞歸:(自頂向下,從大到小)
由上面遞推關系式和初始條件,可以簡單寫出遞歸程序解決此題。由於遞歸過程存在大量的重復計算。因此可以設置全局的標記數組作為備忘錄,避免重復的計算。
但是由於題目要求“如果不能用這些硬幣找零,請給出一種找零方法,使剩下的錢最少”,這就使得采用遞歸方法,如果f(T) = 0時,需要繼續計算f(T-1), f(T-2)……,直到得到f(T-i) !=0。
2、遞推:(自底向上,從小到大)
由遞推關系式:f(T) = min( f(T - vi)) + 1, 其中T-vi < T是恆成立,因此可以保證從小大到遞推,在計算f(T)時,f(T-vi)的值已經得到。
由於f(T)的值需要有f(T-vi)的值得到,因此遞推方法需要數組記錄f(1)……f(T)的值,這樣當f(T) = 0時,可以從f(T)向下遍歷數組,找到第一個f(t) !=0 即可。
在遞推過程中,還可以通過數組記錄,得到每個T是由哪種方式組合得到,使得需要硬幣數最少
遞推代碼見github:硬幣找零之最少硬幣數目
