- 论坛徽章:
- 0
|
Exercise 3.69. 答案
- 生成三元组
- 分析:
[1, 2,...] X [1, 2, ...] X [1,2,...] 构成的三元组,其中分量按下标非严格递增。
可以分成两类,一类是 (1, *, * ) 的,另一类是 [2,3,...] X [2,3,...] X [2,3,...] 形成的三元组。
第一类可以把 1 插入 [1,2,...] X [1,2,...] 形成的二元组,第二类简单地递归。所以有
- (define (triples s)
- (define (f x)
- (lambda (y) (cons x y)))
- (let ((a (stream-car s)))
- (cons-stream
- (list a a a)
- (interleave (stream-map (f a)
- (stream-cdr (pairs s s)))
- (triples (stream-cdr s))))))
复制代码
- 演示:
- > (print-stream (triples integers) 10)
- (1 1 1)
- (1 1 2)
- (2 2 2)
- (1 2 2)
- (2 2 3)
- (1 1 3)
- (3 3 3)
- (1 2 3)
- (2 3 3)
- (1 1 4)
复制代码
- 生成 Pythagoras 三元组
用一个谓词函数去过滤即可
- (define (select x)
- (define (square x) (* x x))
- (let ((a (car x)) (b (cadr x))
- (c (caddr x)))
- (= (+ (square a) (square b))
- (square c))))
- (define Pythagoras
- (stream-filter select (triples integers)))
复制代码
- 演示
- > (print-stream Pythagoras 6)
- (3 4 5)
- (6 8 10)
- (5 12 13)
- (9 12 15)
- (8 15 17)
- (12 16 20)
复制代码
- 作为练习,作者无疑是想让读者使用上述过滤的方式来生成 Pythagoras 三元组。不过这个方法效率很低,事实上我无法计算出第 7 组数。我们看一下上面滤出来的第 6 组数处在流中的什么位置。
- (define (index x s)
- (define (f s i)
- (if (equal? (stream-car s) x) i
- (f (stream-cdr s) (+ i 1))))
- (f s 0))
复制代码
- > (index '(12 16 20) (triples integers))
- 583678
复制代码
- 另一个方法。事实上,Pythagoras 三元组是有公式的。
如果 (a,b,c) 是一个 Pythagoras 三元组,则 (ak, bk, ck) 也是。所以只要求出互素的三元组就可以了,这样的三元组称为本原解。本原解可表示为
(a, b, c) = (s^2-r^2, 2sr, s^2+r^2) ;; 次序不计
其中 (r, s)=1, a+b 为奇数, s>r
所以我们只要用 pairs 生成二元组,并过滤出互素且分量和为奇数的序列,然后把公式 map 上去即可。
- (define (f x)
- (let* ((a (car x))
- (b (cadr x))
- (aa (* a a))
- (bb (* b b)))
- (list (- bb aa) (* 2 a b) (+ aa bb))))
- (define (p x)
- (let ((a (car x)) (b (cadr x)))
- (and (= 1 (gcd a b))
- (odd? (+ a b)))))
-
- (define Fast-Pythagoras
- (cons-stream (list 0 0 0)
- (stream-map f
- (stream-filter p
- (pairs integers integers)))))
复制代码
- 演示:
- (print-stream Fast-Pythagoras 20)
- (0 0 0)
- (3 4 5)
- (5 12 13)
- (15 8 17)
- (35 12 37)
- (7 24 25)
- (21 20 29)
- (63 16 65)
- (99 20 101)
- (45 28 53)
- (143 24 145)
- (9 40 41)
- (195 28 197)
- (77 36 85)
- (255 32 257)
- (323 36 325)
- (117 44 125)
- (399 40 401)
- (483 44 485)
- (55 48 73)
复制代码
为了简洁,我把 (0, 0, 0) 也生成了,它是一个平凡解。前面使用直接过滤生成的 6 组数中,有一些不是本原解,所以在这里没有出现。
[ 本帖最后由 win_hate 于 2009-2-3 20:51 编辑 ] |
|