來自http://www.geeksforgeeks.org/dynamic-programming-set-7-coin-change/web
對於整數N,找出N的全部零錢的表示。零錢能夠用S={s1,s2,s3,..sm}表示,每種零錢的數量爲無窮。請問有多少種找零的方法?less
例如,函數
N = 4,S = {1,2,3},有四種找零方式{1,1,1,1},{1,1,2},{2,2},{1,3},return 4this
N = 10,S= {2,5,3,6} ,有5中找零方式{2,2,2,2,2}, {2,2,3,3}, {2,2,6}, {2,3,5} and {5,5} return 5;google
============
遞歸方法,利用搜索樹spa
1,找出子問題模型:爲了統計全部s結果的數量,咱們能夠將問題分爲兩部分: 結果中不含有硬幣sm, 結果中含有硬幣smrest
函數int count(int S[],int m,int n)計算結果的數量,
函數返回 S[0..m-1]組成的零錢 能夠爲N找零錢的 方法數code
那麼很顯然能夠等價於這二者的和 count(S,m-1,n) + count(S,m,n-S[m-1]),其中count[S,m-1,n]不包括S[m-1]這個硬幣,count(S,m,n-S[m-1])包括了S[m-1]這個硬幣。blog
==遞歸
迭代計算子問題,使用遞歸的方法:
代碼的註釋是爲了求解有多少找零錢的方法,
code的方法是爲了求解全部結果,打印出來
class A{
public: ///returns the count of ways we can sum s[0..m-1] coins to get sum n void help_coinChange(vector<int>& s,int m,int n,vector<int> re){ /// if n is 0 then this is 1 solution (do not include any coin) if(n==0){ for(auto i: re){cout<<i<<" ";}cout<<"-"<<endl; return; } /// if n is less than 0 then no solution exists if(n<0) return; /// if there are no coins and n is greater than 0, there no solution exist //if(m=0 && n>=1) return ; if(m<=0) return ; ///(i) excluding S[m-1] (ii) including S[m-1] help_coinChange(s,m-1,n,re); re.push_back(s[m-1]); help_coinChange(s,m,n-s[m-1],re); } void coinChange(vector<int>& coins, int amount){ vector<int> re; help_coinChange(coins,coins.size(),amount,re); } };
這種方法能夠畫成一顆DFS搜索樹
例如:
1 c[1,2,3],m=3,n=5,re=[] 2 / \ 3 c[],m=2,n=5,[] 4 / \ 5 c[],m=1,n=5,[] 6 / \ 7 c[],m=0,n=5,[] c[],m=1,n=4,[1] 8 / \ 9 c[],m=0,n=4,[1] c[],m=1,n=3,[1,1] 10 / \ 11 c[],m=0,n=3,[1,1] c[],m=1,n=2,[1,1,1] 12 / \ 13 c[],m=0,n=2,[1,1,1] c[],m=1,n=1,[1,1,1,1] 14 / \ 15 c[],m=0,n=1,[1,1,1,1] c[],m=1,n=0,[1,1,1,1,1]====
這麼搜索,會有不少重複的路徑在裏面。
固然咱們也能夠採用BFS的方法來求解 http://bookshadow.com/weblog/2015/12/27/leetcode-coin-change/
代碼在這裏,
==================徹底揹包問題,動態規劃
這個在在揹包問題9講裏講的很詳細,能夠google一下。
代碼在這裏(統計找零錢的種類數)
class A{ public: void dp_coinChange(vector<int> & coins,int amount){ vector<int> re; int n = amount;/// int m = coins.size(); vector<int> re1; vector<int> re2; ///we need n+1 rows as the table is constructed in bottom up manner /// using the base case 0 value case (n=0) int table[n+1][m]; ///fill the enteries for 0 value case (n = 0) for(int i = 0;i<m;i++){ table[0][i] = 1; } ///fill rest the table enteries in bottom up manner for(int i = 1;i< n+1;i++){ for(int j = 0;j<m;j++){ ///count of solutions including S[j] int x = (i-coins[j] >=0)? table[i-coins[j]][j]:0; ///count of solutions excluding S[j] int y = (j >= 1)?table[i][j-1]:0; ///total count table[i][j] = x+y; }cout<<endl; } //return table[n][m-1]; } };
==================================
動態規劃尋找零錢個數最少的解。leetecode 322
給定幾個固定的面值,能夠無限使用。一個目標數,要求用最少的硬幣兌換這個target
解法1,若是每次走給定面值的步數,問對少走多少步能達到目標target,能夠使用bfs的思路求解。
解法2,動態規劃:dp[i] = min{dp[i-c1],dp[i-c2],dp[i-c3],dp[i-c4]...}+1
class Solution { public: int coinChange(vector<int>& coins, int amount){ ///dp[i] = min{dp[i-c1],dp[i-c2],dp[i-c3],dp[i-c4]...}+1 if(amount == 0) return 0; vector<int> dp(amount+1,INT_MAX); dp[0] = 0; for(int i = 1;i<amount+1;i++){ for(int j = 0;j<(int)coins.size();j++){ if(i-coins[j]>=0){ dp[i] = min(dp[i],dp[i-coins[j]]); } } int tmp = (dp[i]==INT_MAX)? INT_MAX: dp[i]+1; dp[i] = tmp; } return dp[amount]==INT_MAX? -1: dp[amount]; } };