Racket 上的动态编程
Dynamic Programing on Racket
所以我有一个练习,我应该计算爬 n 步梯子的方式,有以下限制:你只能上 1、3 或 5 步。
我解决问题的方法是使用这段代码。
(define (climb n)
(cond [(< n 0) 0]
[(<= n 2) 1]
[(= n 3) 2]
[(> n 1) (+ (climb (- n 1)) (climb (- n 3)) (climb (- n 5)))]
)
)
但现在的问题是求出结果太难了,得做很多计算。
有没有可能在球拍上优化这个?代码会是什么样的?如果我能把之前的2个结果保存下来再相加,效果会更好,但我不知道如何。
动态规划的诀窍是存储已经计算过的先前值,这样我们就不必重做昂贵的递归调用。通常我们将值存储在数组、矩阵或散列中 table - 但对于这种情况,我们可以简单地使用一堆参数和尾递归。这有效,而且速度非常快!
(define (climb n)
(if (negative? n)
0
(let loop ([n n] [a 1] [b 1] [c 1] [d 2] [e 3] [f 5])
(if (zero? n)
a
(loop (sub1 n) b c d e f (+ a b c d e))))))
例如:
(climb 100)
=> 20285172757012753619
所以我有一个练习,我应该计算爬 n 步梯子的方式,有以下限制:你只能上 1、3 或 5 步。
我解决问题的方法是使用这段代码。
(define (climb n)
(cond [(< n 0) 0]
[(<= n 2) 1]
[(= n 3) 2]
[(> n 1) (+ (climb (- n 1)) (climb (- n 3)) (climb (- n 5)))]
)
)
但现在的问题是求出结果太难了,得做很多计算。 有没有可能在球拍上优化这个?代码会是什么样的?如果我能把之前的2个结果保存下来再相加,效果会更好,但我不知道如何。
动态规划的诀窍是存储已经计算过的先前值,这样我们就不必重做昂贵的递归调用。通常我们将值存储在数组、矩阵或散列中 table - 但对于这种情况,我们可以简单地使用一堆参数和尾递归。这有效,而且速度非常快!
(define (climb n)
(if (negative? n)
0
(let loop ([n n] [a 1] [b 1] [c 1] [d 2] [e 3] [f 5])
(if (zero? n)
a
(loop (sub1 n) b c d e f (+ a b c d e))))))
例如:
(climb 100)
=> 20285172757012753619