八皇后问题:在NXN的棋盘中放置8个皇后,使之不相互攻击
相互攻击:指两个皇后处于同一行或同一列,斜线
以4X4棋盘为例
假设将第一个皇后放在第一个格子里,在符合条件的格子里任意挑选下一个格子
符合条件的格子:'((posn 1 2) (posn 1 3) (posn 2 2) (posn 2 3) (posn 3 1) (posn 3 2))
设置一个辅助函数形成符合条件的格子
如果下一个格子挑选(posn 1 2)(挑选列表的第一个),假设就这样一直递归下去,选(posn 1 2)失败了
那就要掉过头来重新挑选上一个,如果出现了能解决八皇后问题的情况,就直接输出true,否则就这样一直往上重新挑选。
这种算法称为回溯(backtrack),回溯是向上推导,即发现不满足条件的路径,就向上返回寻求其他的路径。最常见的回溯就是迷宫。
(define (change posn1 list)
(cond
[(empty? list) empty]
[else
(local ((define pos (first list)))
(cond
[(cons? pos)
(append (change posn1 pos)
(change posn1 (rest list)))]
[(and (posn? pos) (not (threatened? posn1 pos)))
(cons pos (change posn1 (rest list)))]
[else (change posn1 (rest list))]))]))
辅助函数:生成符合条件的格子列表
(define (place-queen n list)
(placement? n list 0))
(define (placement? n list flag)
(cond
[(= n 0) true]
[(empty? list) false]
[else (local ((define (possible? n list flag)
(axuliary n list flag)))
(cond
[(cons? (first list))
(or (placement? n (first list) flag)
(placement? n (rest list) flag))] ;;对所有格子进行讨论
[else
(cond
[(possible? n list (add1 flag)) ;;回溯
(axuliary n list (add1 flag))]
[else (placement? n (rest list) flag)])]))]))
其中(possible? n list flag)是对当前要走路径是否为解的讨论,如果可以,就走,否则,重新选择另一条路。
(define Graph (build-board 4 make-posn))
(define (axuliary n list flag)
(cond
[(= flag 1) (placement? (sub1 n) (change (first list) Graph) flag)]
[else (placement? (sub1 n) (change (first list) list) flag)]))
flag变量是对list不同情况一种区分
example:
(在不加flag情况下)
选第一个格子
->(placement? 4 '((posn 1 2) (posn 1 3) (posn 2 2) (posn 2 3) (posn 3 1) (posn 3 2)))
->(axuliary n list)
->(placement? (sub1 n) (change (first list) list))
其中处理的list 是 '((posn 1 2) (posn 1 3) (posn 2 2) (posn 2 3) (posn 3 1) (posn 3 2))
第一次处理的list应该是整个list,之后才是筛选后的list,所以要分情况讨论