八皇后问题
【题目】国际象棋的棋盘是 8 x 8 的格子。皇后的威力最大,她可以横向,竖向,对角线方向攻击任意距离的其它棋子。
现在要把8个皇后放在棋盘上,使她们不要互相攻击,有多少种放摆放的方法?
分析: 为了不互相攻击,显然每一行必须且只能放一个皇后。并且每一行的皇后在竖直的位置都不能相同。
可以用一个数组来表达最后的解,比如:[5,3,6,0,2,4,1,7]
就表示,第一行的皇后放在第5格,第二行皇后放在第3格,…
注意,是从第 0 格算起的。
所有可能的解,显然就是: [0…7] 的全排列。
然后筛选出对角线方向互相不攻击的即可。
import Data.List (permutations)
queen :: [[Int]]
queen = filter f (permutations [0..7])
where
f [] = True
f (x:xs) = f xs && g 1 x xs
g _ _ [] = True
g n x (y:ys) = abs (x-y) /= n && g (n+1) x ys
main :: IO ()
main = do
print $ head queen
print $ length queen
代码很短,核心逻辑是判断对角线是否相互攻击。
对角线攻击的充分必要条件是:两个子的水平距离等于垂直距离。
92种放法中,很多都是重复的。通过对一种解法进行旋转、镜像变换就可以得到8种方法。
如何去掉这些重复呢?
我们需要一个函数,给定一个局面,可以返回所有的同像局面