换硬币问题
问题
给了 50 美分,25 美分,10 美分,5 美分,1 美分的硬币,将 1 美元换成零钱,一共有多少种不同的方式?
思想
总的方式 = 总的方式(有 50 美元)+ 总的方式(除了 50 美元),以 50 美元为例
子问题的边界情况:
总的方式(现金 a 换成 n 种硬币)= 总的方式(现金 (a - 50) 换成 n 种硬币)+ 总的方式(现金 a 换成 n-1 种硬币),以 50 美元为例
稍微抽象一下就是:总的方式(现金 a 换成 n 种硬币)= 总的方式(现金 a - d 换成 n 种硬币)+ 总的方式(现金 a 换成 n-1 种硬币)
开始边界:a = 100, n = 5
结束边界:
- a = 0, 表示的意思是所有的钱正好都换完,所以算是 1 种换零钱的方式。 如果打算写个通用的程序,比如说初始 a = 100 不固定,那么 a = 0 也可能是我本来就没钱,所以应该算是 0 种换零钱的方式
- a < 0, 表示的意思是最后剩下的钱不够换,所以算是 0 种换零钱的方式
- n = 0, 表示的意思是可以换的硬币有 0 种,所以算是 0 种换零钱的方式
代码
(define (cc a n) ; 总的方式(现金 a 换成 n 种硬币)
(cond ((= a 0) 1) ; 边界, a=0
((or (< a 0) (= n 0)) 0) ; 边界, a<0 和 n = 0
(else (+ (cc (- a (d n)) n) ; 总的方式(现金 a - d 换成 n 种硬币)
(cc a (- n 1)))))) ; 总的方式(现金 a 换成 n - 1 种硬币)
;方便理解,假设如下
;可换 5 种硬币 (n = 5), 那么假设需要除去 50 美分,所以 d = 50
;可换 4 种硬币,那么假设需要除去 25 美分,所以 d = 25
;...
;既然是假设,那么如下假设也是一样的
;(define (d n)
; (cond ((= n 1) 50)
; ((= n 4) 25)
; ((= n 2) 10)
; ((= n 3) 5)
; ((= n 5) 1)))
(define (d n)
(cond ((= n 5) 50)
((= n 4) 25)
((= n 3) 10)
((= n 2) 5)
((= n 1) 1)))
(define (count-change a)
(cc a 5)) ; 边界, 有 5 种硬币
(count-change 100) ; 边界, 有 100 美分