算法筆記——硬幣找零之最少硬幣數


題目來源:NYOJ995

問題描述:

  在現實生活中,我們經常遇到硬幣找零的問題,例如,在發工資時,財務人員就需要計算最少的找零硬幣數,以便他們能從銀行拿回最少的硬幣數,並保證能用這些硬幣發工資。

  我們應該注意到,人民幣的硬幣系統是 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 不能被硬幣系統中的硬幣找零,請輸出剩下錢數最少的找零方案中的最少硬幣數。

分析:

  假設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:硬幣找零之最少硬幣數目


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM