硬币面值组合的算法题解

方法一 转自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;
}



posted on 2017-08-02 19:54  ljbguanli  阅读(514)  评论(0编辑  收藏  举报