欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

关于SICP中练习3.66

程序员文章站 2024-02-10 23:37:28
...

起初在做这题的时候,第一时间想到的是写一个迭代过程和一个计数器相互配合,循环地比较pairs流中每个数对,当和(1, 100)或是(100, 100)相等的时候,就把计数器的值输出就可以了(假设是从0开始标记第一个数对的)。但是理想很丰满,现实很骨感。前者(1, 100)能按照这个思路很快就可以得出答案来(197),但是后者直接内存溢出了,说明这个序对应该排在非常得后面。正如我下面的分析,也证实了这一点。
首先,我们来写一个辅助打印的过程,这样就能比较容易地找出规律了,永远记住一点,把弱智又烦人的事情交给计算机去做,从而把自己的精力解放出来花在更有意义的事情上。

; 同时打印 m个流的前 n 项
(define (show-streams n . streams)
    (if (accumulate
            (lambda (a b) (or a b))
            #f
            (cons (= n 0) (map stream-null? streams)))
        (newline)
        (begin
            (display-line (map stream-car streams))
            (apply show-streams (cons (- n 1) (map stream-cdr streams))))))

有了这个辅助过程,我们就可以这样做:

(show-streams 17 (cons-stream 0 integers) (pairs integers integers))

这样找规律的时候就轻松多了。比如我上面的这行代码,就从第0号序对开始,一直分行打印到了第16号序对。
然后按照书上的逻辑,我们可以设一个二元整标函数 f(i, j),而i与j合起来就是所对应的序对,而函数值就是这个序对在流pairs中的位置。将这些函数值放在如书本236页中类似的二维网格图中时,我们不难总结出 f(i, j) 函数的如下约束:
f(i+1, j+1) = 2*[f(i, j) + 1]
f(0, j) = 2j - 1
f(0, 0) = 0
(i, j ∈ N+) & (i =< j)
于是,我们惊奇地发现,这是一个二阶偏差分方程。就这样,一道看似是CS的题目,其实本质是一道数学题。
我们首先观察一下这个偏差分方程
f(i+1, j+1) = 2
[f(i, j) + 1]
当不去考虑它的约束条件时,发现其实它是一个关于变元对称的方程,比如将f(j, i)带入原方程,仍可以成立。这样就启发我们可以根据变元的对称性去解方程,分两种情况:
当 i = j 时,设 i = k,那么原方程就变成:
f(k+1, k+1) = 2*[f(k, k) + 1]
这样就可以再令 a(k) = f(k, k) , 于是原方程可以化简成:
a(k+1) = 2*[a(k) + 1] 并且 a(0) = f(0, 0) = 0
上面这个方程我想高中生都应该会解了吧,那我就直接给答案了:
f(i,j) = 2^(i+1) - 2 (当 i = j)

当 i < j 时 , 可设 k = j - i
然后观察原方程与边界条件 f(0, j) = 2j - 1 后不难发现,k其实递归到最后就变成边界条件上的一个常数了。因此,可以再将原方程化简为:
f(i, i+k) = 2
[f(i-1, i-1+k) + 1]
这样就可以再令 a(i) = f(i, i+k) , 于是原方程可以化简成:
a(i) = 2*[a(i-1) + 1] 并且 a(0) = f(0, k) = 2k - 1
上面是一个一阶线性非齐次常差分方程,于是可以求得其通解为:
a(i) = C
2^i - 2
然后根据 a(0) = 2k - 1 可以得到 C = 2k + 1 = 2*(j - i) + 1
所以得到:
f(i,j) = [2*(j - i) + 1]*2^i - 2 (当 i < j)

宗上可得:
f(i,j) = 2^(i+1) - 2 (当 i = j)
[2*(j - i) + 1]*2^i - 2 (当 i < j)

但是,习题中的 (pairs integers integers) 里的 integers 流是从 1 开始展开的,所以,上述公式如果要直接用在练习中还需加一个自变量的线性变换,令:
p = i + 1
q = j + 1
于是我们有:
g(p, q) = 2^p - 2 (当 p = q)
[2*(p - q) + 1]*2^(p-1) - 2 (当 p < q)
于是可以得到:
g(1, 100) = 197
g(100, 100) = 2^100 - 2
可见真的好大,怪不得内存会溢出。

相关标签: scheme