首页 > 代码库 > 找零问题

找零问题

问题描述:

为找零问题 设计一种动态规划算法:给定金额n以及各种面额d1,d2,...,dm的数量无限的硬币,求总金额等于n的硬币的最少个数,或者指出该问题无解。

(对于该问题可以用动态规划方法或者贪婪法求解,但贪婪法要注意如何说明局部最优可以保证全局最优)

思路: 

各种硬币的面额为 d[1,2,3,..N],设C[i,j]为在前i种面额中求总面值为j的最优解(最少硬币数)。
初始化 
C[i,j] = 正无穷 (i=0, j>=1 && j<=N)
c[i,j] = 0(i>=0 && i<=M ,j=0)
正无穷表示无解。


前i种面额中总价值为j可以分为以下几种情况:
不包含第i中面额的硬币...
包含1个第i中面额的硬币...
包含2个第i中面额的硬币...
...
包含k个第i中面额的硬币... (j-d[i]*k>=0)


如果总价值为j的金额包含k个第i种面额,而第i种硬币的面额值为d[i],则前i-1种硬币只需求凑齐金额为j-d[i]*k的最优解,

所以可以建立如下的递推关系:
C[i,j] = min(C[i-1,j-d[i]*k] + k) , 其中j-d[i]*k >=0


例子:

已知四种面额为4,2,3,5的硬币,求总金额等于7的硬币的最少个数。

很明显可以看出该问题中

两枚硬币的组合方式:

7=4+3,7=5+2,

三枚硬币的组合方式:

7=2+2+3 

所以最少硬币数为2

下面利用动态规划算法求解最少硬币数。

#include <iostream>
#include <iomanip>

const int M = 4;
const int N =7;
const int KIND = 4;
const int MAX_INIFINITE = 10000;
int c[M+1][N+1];


using namespace std;

int d[KIND + 1] = {0,4,2,3,5};
int findmoney(int i,int j);
int min(int x,int y);

int main()
{
	
	int i;
	int j;

	for(i = 0;i<=M;i++)
		for(j = 0;j<=N;j++)
			c[i][j] = MAX_INIFINITE;

	for(i = 0;i<=M;i++)
		c[i][0] = 0;

	//call
	c[M][N] = findmoney(M,N);//

	if(c[M][N] < MAX_INIFINITE)
		cout << "总金额为" << N << ",则至少需要的硬币个数为:" << c[M][N] << endl;
	else
		cout << "No answer" << endl;

	

	for(int i = 0;i<=M;i++)
	{
		for(int j = 0;j<=N;j++)
		{
			cout << setw(8) << setiosflags(ios::left);
			cout << c[i][j] << " ";
		}
		cout << endl;
	}
	return 0;
}

int findmoney(int i,int j)
{
	int k = 0;
	int value = http://www.mamicode.com/MAX_INIFINITE;>


分析输出矩阵C[M+1][N+1]可以知道,从上图中绿色下划线标记可以知道,通过自顶向下的方式计算C[4][7]的值,仅需要知道C[1,4],C[2,2],C[2,4],C[3,2],C[3,7]

同样的。如果N = 1,则输出"No answer"


附:网上搜集的与找零问题相关的具体问题的解答:


找零问题有解及其面值组成

动态规划求解硬币找零问题

上面两篇章文章给出的方案和算法中能求出有解的情况,并给出具体应该是哪几个面值的硬币,而且面值中含有面额为1的硬币。对无解的情况没有处理。


找零问题 完全背包

该文讨论的是凑齐给定金额的方式有几种。