SICP 2.42八个皇后。帮助检查我的代码有什么问题?

时间:2012-09-11 06:14:47

标签: lisp scheme sicp mit-scheme

该程序将生成八个皇后的所有可能结果。 我使用一个列表,它将行号作为数据结构。 但是当我运行它时,我得到了错误的结果。 这是我的代码:

(define (queens board-size)
  (define (safe? k position)
    (define (iter last-element front-lst col-num k)
      (define (ok? l-e car-lst)
    (and (not (= l-e car-lst))
         (not (= (abs (- l-e car-lst)) (abs (- k col-num))))))
      (if (null? front-lst)
      true
      (and (ok? last-element (car front-lst))
           (iter last-element (cdr front-lst) (++ col-num) k))))
    (let ((l-e (car (my-reverse position)))
      (f-l (my-remove (car (my-reverse position)) position)))
      (iter l-e f-l 1 k)))

  (define empty-board nil)

  (define (adjoin-position new-row k rest-of-queens)
    (append rest-of-queens (list new-row)))

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

2 个答案:

答案 0 :(得分:1)

我怀疑你的做法太复杂了。 你需要做的是:

找到符合两个标准的下一个女王的新行号:1)它尚未包含2)新行号与任何已使用的行号之间的差异不等于两行的距离。

在递归中执行此操作。

我的CL解决方案供参考:

(defun fits (p list)
  (and (not (member p list))
       (loop for i in list as j from 1
            never (eql (abs (- p i)) j))))

(defun backtrack (list)
  (if (eql (length list) 8)
      (print list)
      (loop for i from 1 to 8
         when (fits i list)
           do (backtrack (cons i list)))))

运行
(backtrack nil)

答案 1 :(得分:1)

我今天刚刚在SICP完成了这个问题,所以我会尽力帮助:

我用my-remove测试了你的代码:

(define (my-remove num num-list)
    (cond   ((null? num-list) nil)
            ((= num (car num-list)) (cdr num-list))
            (else (cons (car num-list) (my-remove num (cdr num-list))))))

测试:

(let ((result (queens 8)))
(display (length result))(newline)
(map (lambda (possible-solution) (display possible-solution)(newline)) result)
)

返回 92 。 。 (3 7 2 8 5 1 4 6) (3 7 2 8 6 4 1 5) 。

92个结果,其中一个是书中的解决方案

这是你的代码的一部分(稍微)重构,我摆脱了my-remove,并使用了let *。 我不打算重构整个事情,但我至少试图在变量名中添加含义。 这些变化有点快: (还添加了一些评论)

;no major refactoring, essentially removed my-remove and some refactors
(define (queens board-size)
  (define (safe? k position)
    (define (iter last-element front-lst col-num k)
        ;what's ok?
      (define (ok? l-e car-lst)
            (and (not (= l-e car-lst))
                (not (= (abs (- l-e car-lst)) (abs (- k col-num))))))
      (if (null? front-lst)
      true
      (and (ok? last-element (car front-lst))
           (iter last-element (cdr front-lst) (++ col-num) k))))
    ;queens means a list of rows, each representing a queen position
    ;that is, when queens[col] = row  that means there's a queen in row 'row and 
    ;column 'col

    ;reimplementing removing the queen, and the let turned to let*
    (let* ((reverse-column-queens (my-reverse position))
           (last-queen (car reverse-column-queens))
        ;remove that queen from the list
        ;btw 'position is actually 'positions
        (all-other-queens (my-reverse (cdr reverse-column-queens))))
      (iter last-queen all-other-queens 1 k)))
.
.
.

所以,我猜你使用的my-remove可能是错的。

现在,你的变量的名称并不是非常具有描述性,因此它会增加一个已经混乱的代码(对于本练习的作者或你来说没有任何冒犯)。