一,問題描述html
假設有 m 種面值不一樣的硬幣,存儲在 coinsValues數組中,現須要使用這些硬幣來找錢,各類硬幣的使用個數不限。 求對於給定的錢數N,咱們最多有幾種不一樣的找錢方式。硬幣的順序並不重要。算法
二,動態規劃分析數組
爲了更好的分析,先對該問題進行具體的定義:將用來找零的硬幣的面值存儲在一個數組中。以下:post
coinsValues[i] 表示第 i 枚硬幣的面值。好比,spa
第 i 枚硬幣 面值code
1 1htm
2 3blog
3 4遞歸
待找零的錢數爲 n (上面示例中 n=6)get
爲了使問題總有解,通常第1枚硬幣的面值爲1
設 c[i,j]表示 使用 第 1,2,...i 種面值的硬幣時,須要找金額爲 j 的錢,最多可採用多少種不一樣的方式?
i 表示可用的硬幣種類數, j 表示 須要找回的零錢
①最優子結構
對於某種面值的硬幣,要麼使用了(可能使用屢次)它,要麼不使用它。故:
c[i,j]=c[i-1,j] + c[i,j-coinsValue[i]]
c[i-1,j] 表示不使用第 i 枚硬幣, c[i, j-coinsValue[i]] 表示至少使用了一次 第 i 枚硬幣。c[i, j-coinsValue[i]] 表示,第 i 枚硬幣還能夠繼續使用。由於第一個參數仍是 i
從這裏能夠看出:用到了《組合數學》中的加法原理。
如何肯定初始(基準)條件?一個重要的方法就是畫一個簡單的實例圖。(借用網上一張圖:)
C({1,2,3},j) --> recursiveChargeTypes
C({1,2,3}, 5)
/ \
/ \
C({1,2,3}, 2) C({1,2}, 5)
/ \ / \
/ \ / \
C({1,2,3}, -1) C({1,2}, 2) C({1,2}, 3) C({1}, 5)
/ \ / \ / \
/ \ / \ / \
C({1,2},0) C({1},2) C({1,2},1) C({1},3) C({1}, 4) C({}, 5)
/ \ / \ / \ / \
/ \ / \ / \ / \
. . . . . . C({1}, 3) C({}, 4)
/ \
/ \
. .
好比,按照紅色那條路走,就知道 5 使用了硬幣面值3 和 2,故成功找零,此時 j=0了,這是一種找零方式 ==》 當j==0時,返回1
三,代碼實現
public class DPCoinCharge { public static int chargeTypes(int[] coinsValues, int n){ int m = coinsValues.length; int[][] c = new int[m+1][n+1]; //基準條件,可參考下面的遞歸代碼 for(int i = 0; i <=m; i++) c[i][0] = 1; for(int i = 1; i <=n; i++) c[0][i] = 0; for(int i = 1; i <=m; i++) { for(int j = 1; j <=n; j++) { if(j < coinsValues[i-1])//第 i 枚硬幣 不可用. (須要找 5塊錢,可是如今只有一張百元大鈔) { c[i][j] = c[i-1][j]; continue; } //在第 i 枚硬幣可用的狀況下, 不使用 第 i 枚硬幣 或者第 i 枚硬幣至少使用一次---狀態方程 c[i][j] = c[i-1][j] + c[i][j - coinsValues[i-1]];//coinsValues下標從0開始 } } return c[m][n]; } //遞歸實現 public static int recursiveChargeTypes(int[] coinsValues, int m, int n) { //基準條件 能夠 經過畫一個簡單的實例 分析來得出. 好比 recursiveChargeTypes({1,3,4}, 3, 5) if(n == 0) return 1; if(n < 0) return 0; if(m <= 0) return 0; else return recursiveChargeTypes(coinsValues, m-1, n) + recursiveChargeTypes(coinsValues, m, n-coinsValues[m]); } public static void main(String[] args) { int[] coinsValues = {1,2,3}; int n = 5; int maxTypes = chargeTypes(coinsValues, n); System.out.println(maxTypes); } }
四,參考資料
http://www.acmerblog.com/dp6-coin-change-4973.html