SICP 全笔记

Exercise 2.43. Louis Reasoner is having a terrible time doing exercise 2.42. His queens procedure seems to work, but it runs extremely slowly. (Louis never does manage to wait long enough for it to solve even the 6× 6 case.) When Louis asks Eva Lu Ator for help, she points out that he has interchanged the order of the nested mappings in the flatmap, writing it as

(flatmap
 (lambda (new-row)
   (map (lambda (rest-of-queens)
          (adjoin-position new-row k rest-of-queens))
        (queen-cols (- k 1))))
 (enumerate-interval 1 board-size))

Explain why this interchange makes the program run slowly. Estimate how long it will take Louis’s program to solve the eight-queens puzzle, assuming that the program in exercise 2.42 solves the puzzle in time T.

这个效率低下的整个过程如下:

(define (queens board-size)
  (define (queen-cols k)
    (if (= k 0)
        (list empty-board)
        (filter
         (lambda (positions) (safe? k positions))
         (flatmap
          (lambda (new-row)
            (map (lambda (rest-of-queens)
                   (adjoin-position new-row k rest-of-queens))
                 (queen-cols (- k 1))))
          (enumerate-interval 1 board-size)))))
  (queen-cols board-size))

我们可以倒着,从 k = 1 的时候开始分析。

k = 1 的时候,flatmap 去执行的过程 (lambda (new-row)..) 会被调用 board-size 次。 其中的每一次将会去调用 (lambda (rest-of-queens)..) 这个过程 (queen-cols (- k 1)) 次。

正确的调用过程,queen-cols 总共仅被调用 8 次而已。但在这个效率不高的过程里,当 board-size 为 8 , k = 1 的时候,(queen-cols 0) 被调用了 8 次。k = 2 的时候,(queen-cols 1) 被调用了 8 次,(queens-cols 0) 被调用了 64 次。以此类推,k = 8 的时候,

  • (queen-cols 7) 被调用了 8 次
  • (queen-cols 6) 被调用了 64 次
  • (queen-cols 5) 被调用 $8^3$
  • 可以知道,(queen-cols n) 会被调用 $8^{8-n}$

如果以前正确的过程需要时间 T,那么现在的过程则需要时间:

$$\frac{8^1+8^2+8^3+8^4+8^5+8^6+8^7+8^8}{8} \times T = 2396741 \times T$$