In England the currency is made up of pound, £, and pence, p, and there are eight coins in general circulation:
1p, 2p, 5p, 10p, 20p, 50p, £1 (100p) and £2 (200p).
It is possible to make £2 in the following way:
1×£1 + 1×50p + 2×20p + 1×5p + 1×2p + 3×1p
How many different ways can £2 be made using any number of coins?
在英格兰货币由英镑和便士组成,一般流通中有八个硬币:
1p,2p,5p,10p,20p,50p,£1(100p)和£2(200p)。
可以通过以下方式赚取2英镑:
1×£1 + 1×50p + 2×20p + 1×5p + 1×2p + 3×1p
使用任意数量的硬币可以使用多少种不同的方式?
思路
递归求解:k代表有几种面值的硬币,n代表构成的钱数
边界条件:当只有一种面值的硬币的时候,只能有一种解决方法
当所求值钱数为0时,表示只有一种解决方法
当所求值<0时,不会有解决方法
递归调用函数 f(k - 1, n) + f(k, n - money[k]);
#include <stdio.h>
int money[9] = {0, 1, 2, 5, 10, 20, 50, 100,200};
int f(int k, int n){
if(k == 1) return 1;
if(n == 0) return 1;
if(n < 0) return 0;
return f(k - 1, n) + f(k, n - money[k]);
}
int main(){
printf("%d\n",f(8,1000));
return 0;
}
记忆化
在这道题中由于200并不是一个很大的数字,所以递归调用的次数并不算多,但是如果处理更大数值的话,我们可以看出用时十分长。在这里,我们像14题一样继续用记忆化的方法,记录已经求解过的值。
1.开辟二维数组keep;
2.当数组中有值时,直接返回数组中的值;
3.当数组中没有值时,更新keep数组。
#include <stdio.h>
#define max 1000
#define K 8
int money[9] = {0, 1, 2, 5, 10, 20, 50, 100,200};
int keep[K][max + 5] = {0};
int f(int k, int n){
int ans = 0;
if(k == 1) return 1;
if(n == 0) return 1;
if(n < 0) return 0;
if(keep[k][n] && k < K && n < max){
return keep[k][n];
}else{
ans = f(k - 1, n) + f(k, n - money[k]);
}
if(k < K && n < max){
keep[k][n] = ans;
}
return ans;
}
int main(){
printf("%d\n",f(8,200));
return 0;
}