硬币面值组合的算法题解
方法一 转自http://www.cnblogs.com/python27/archive/2013/09/05/3303721.html
动态规划的方法,是将m*n(m表示硬币的种类,n表示所要组成的和)的辅助数组,
个人觉得这样的方法的缺点是 较难理解,计算时间和辅助空间占用较多
方法二 參考http://blog.csdn.net/randyjiawenjie/article/details/6335208
这样的方法是用递归的方式实现,个人认为此方法在克服动态规划的缺陷上有较好的表现
以下是对两种算法的实现
#include <stdio.h> #include <list> #include <vector> using namespace std; list<int> myList; int count = 0; /********************************* * numbers Combinations: using recursive algorithm * Basic idea: * 输入两个整数n和sum,从数列1,2,3,……n中任意取几个数。使其和等于sum。 * 要求将全部的可能组合列出来 **********************************/ void findSum(int sum,int n) { if(n<1 || sum <1) { return ; } if(sum > n) { myList.push_back(n); findSum(sum-n,n-1); myList.pop_back(); findSum(sum,n-1); } else if(sum == n) { count++; list<int>::iterator it = myList.begin(); while(it != myList.end()) { printf(" %d",*it++); } printf(" %d",n); printf(" count = %d\n",count); } else{ } } void findRecursive(int sum,int n[],int index) { if(index < 0 ) { return ; } if(sum >= n[index]) { for(int i=1;i<= sum/n[index];i++) {//printf(" sum=%d,i*n[index]=%d \n",sum,i*n[index]); myList.push_back(i); myList.push_back('*'); myList.push_back(n[index]); if(sum-i*n[index] == 0) { count++; list<int>::iterator it = myList.begin(); while(it != myList.end()) { if(*it != 42) printf(" %d",*it); else printf("*"); it++; } printf(" count = %d\n",count); } findRecursive(sum-i*n[index],n,index-1); myList.pop_back(); myList.pop_back(); myList.pop_back(); } findRecursive(sum,n,index-1); } else if(sum == n[index]) { count++; list<int>::iterator it = myList.begin(); while(it != myList.end()) { if(*it != 42) printf(" %d",*it); else printf("*"); it++; } if(sum != 0) printf(" %d",n[index]); printf(" count = %d\n",count); } else{ } } /**************************************************************** * coin Combinations: using dynamic programming * * Basic idea: * dp[i][j] = sum(dp[i-1][j-k*coins[i-1]]) for k = 1,2,..., j/coins[i-1] * dp[0][j] = 1 for j = 0, 1, 2, ..., sum * * Input: * coins[] - array store all values of the coins * coinKinds - how many kinds of coins there are * sum - the number you want to construct using coins * * Output: * the number of combinations using coins construct sum * * Usage: * c[3] = {1, 2, 5}; * int result = coinCombinations(c, 3, 10); * ****************************************************************/ int findDP(int sum,int coins[], int coinKinds) { // 2-D array using vector: is equal to: dp[coinKinds+1][sum+1] = {0}; vector<vector<int> > dp(coinKinds+1); int i=0; for(i=0;i<=coinKinds;i++) { dp[i].resize(sum+1); } for(i = 0; i<=coinKinds;i++) { for(int j=0;j<=sum;j++) { dp[i][j] = 0; } } //init: dp[i][0] = 1; i = 0, 1, 2 ..., coinKinds //Notice: dp[0][0] must be 1, althongh it make no sense that //using 0 kinds of coins construct 0 has one way. but it the foundation //of iteration. without it everything based on it goes wrong for(i=0;i<=coinKinds;i++) { dp[i][0] = 1; } //iteration: dp[i][j]= sum(dp[i-1][j-k*coins[i-1]) //k = 0,1,2,3,...,j/coins[i-1] for (i = 1; i <= coinKinds; ++i) { for (int j = 1; j <= sum; ++j) { dp[i][j] = 0; for (int k = 0; k <= j / coins[i-1]; ++k) { dp[i][j] += dp[i-1][j - k * coins[i-1]]; } } } return dp[coinKinds][sum]; } int main() { int m,n; int i,j; int a[]={5,2,1}; m = 20,n=9; // findSum(10,n); findRecursive(10,a,2); // count = findDP(10,a,3); printf("find %d times\n",count); return 0; }