换零钱 动态规划解法 C语言描述

题目

已知有三种人民币,分别为1元、2元、5元。求10元可以有多少种换成上述三种零钱的方法(不限制每种人民币的数量)。

原理

设有a种面值的人民币,设总价格为b,取a种面值中的一种,设其面值为d,则有:

使用a种面值将总价格b换取零钱的方法数量 =

使用a种面值将总价格(b-d)换取零钱的方法数量 + 使用(a-1)种面值将总价格b换取零钱的方法的数量(其中没有面值d的人民币)

可以对照下表理解原理:

1元 1元、2元 1元、2元、5元
1, 1,2 1,2,5
0元 0 1 1 1
1元 1 1 1 1
2元 2 1 2 2
3元 3 1 2 2
4元 4 1 3 3
5元 5 1 3 4
6元 6 1 4 5
7元 7 1 4 6
8元 8 1 5 7
9元 9 1 5 8
10元 10 1 6 10

如果设上表为二维数组A,横向表头取值11,21,2,5,纵向表头取值为1~10。一些具体的等式如下:

A[2][1,2] = A[0][1,2] + A[2][1] = 1 + 1 = 2
A[3][1,2] = A[1][1,2] + A[3][1] = 1 + 1 = 2
A[4][1,2] = A[2][1,2] + A[4][1] = 2 + 1 = 3
A[5][1,2] = A[3][1,2] + A[5][1] = 2 + 1 = 3
A[6][1,2] = A[4][1,2] + A[6][1] = 3 + 1 = 4
A[5][1,2,5] = A[0][1,2,5] + A[5][1,2] = 1 + 3 = 4
A[6][1,2,5] = A[1][1,2,5] + A[6][1,2] = 1 + 4 = 5
A[9][1,2,5] = A[4][1,2,5] + A[9][1,2] = 3 + 5 = 8
A[10][1,2,5] = A[5][1,2,5] + A[10][1,2] = 4 + 6 = 10

代码

如果理解了原理,那么代码很简单。唯一需要注意的是,我们不需要保存中间量,因此一维数组完全可以胜任,秘密在于分层计算,这一步累加最为重要A[j] += A[j - kind[i]];

#include <stdio.h>

int count_change(int n)
{
	int A[n + 1];
	int kind[3] = {1, 2, 5};
	A[0] = 1;
	for (int j = 1; j <= n; j++)
		A[j] = 0;
	for (int i = 0; i < 3; i++)
	{
		for (int j = kind[i]; j <= n; j++)
		{
			A[j] += A[j - kind[i]];
		}
		for (int j = 0; j <= n; j++)
		{
			printf("%d ", A[j]);
		}
		printf("

");
	}
	return A[n];
}

int main(void)
{
	int result = count_change(10);
	printf("%d
", result);
	return 0;
}
原文地址:https://www.cnblogs.com/pkuimyy/p/14144916.html