10分
题目:找零钱
现在有1分、5分、1角、两角五分、五角的零钱,给出计算换零钱种类的算法。
例如:17分钱有6种换零钱的方法
1个1角 1个5分 2个1分
1个1角 7个1分
3个5分 2个1分
2个5分 7个1分
1个5分 12个1分
17个1分
(1)思路分析:
每一种方法中,有最大零钱,这个信息。
change (n, max)
change (17, 10) 有2种
change (17, 5) 有3种
change (17, 1) 有1种
所以,这是一个最大零钱逐渐变小的递归过程。
考虑这样的可能性,17分钱换出一个1角,后变成了7分钱换零钱的问题,即(17,10)->(7,5) and (7,1)。但其实,这里有坑不是直接变的。
只计算有多少种换零钱的方法,而不考虑具体的数额。代码:
#include
int c[5] = {1, 5, 10, 25, 50};
int change(int n, int i){
if(0 == n) return 0;
if(0 == i) return 1;
if(n
(2)分析: 顺着思路想,其实这个问题可以画出一棵树,树的叶子节点的个数就是解。那么,其实问题的本质就是一个二叉树的搜索问题,求叶子节点个数的问题。而,每一条路径对应的就是每种换零钱方式的具体数额。
考虑使用一种void类型的函数实现。就需要用一个显示的变量来存储这个方法种类个数。另外,零钱集合可以放在数组中,只要传递一个数组指针给函数。
#include
void change(int n, int *c, int i, int *sum){
if(0 == n) return;
if(0 == i) {
*sum += 1;
return;
}
change(n, c, i-1, sum);
if(n >= c[i])
change(n-c[i], c, i, sum);
}
int main(void) {
// your code goes here
int c[5] = {1, 5, 10, 25, 50};
int sum = 0;
change(17, c, 4, &sum);
printf("%d\n", sum);
return 0;
}
(3)问题:如何输出每种换零钱的具体数额。
类似于二叉树的深度优先搜索,每搜索到一个叶子节点就输出该路径。一条路径结束之后,要回退。常用的操作就是,栈的push和pop操作。这里只需要对零钱的数字进行加减就行。
要输出每种零钱的具体换算数额,需要创建一个数组来保存数据。
假设数组为A[5] ={0}, A[i]保存C[i]的个数。
#include
void change(int n, int *c, int i, int *sum, int *a){
if(0 == n) return;
if(0 == i) {
*sum += 1;
a[i] = n;
print(c, a, 4);
a[i] = 0;
return;
}
if(n >= c[i]){
a[i]++;
// 如果剩余的钱大于最大零钱,减去,继续搜索
change(n-c[i], c, i, sum, a);
a[i]--;
}
// 如果剩余的钱小于最大零钱,降级,继续搜索
change(n, c, i-1, sum, a);
}
void print(int *c, int *a, int n){
for(int i=n-1; i>=0; i--){
if(a[i])
printf("%d个%d分\t", a[i], c[i]);
}
printf("\n");
}
int main(void) {
// your code goes here
int a[5] = {0};
int c[5] = {1, 5, 10, 25, 50};
int sum = 0;
change(30, c, 4, &sum, a);
printf("一共有%d种换零钱的方式。", sum);
return 0;
}