芯有所想

精益求精

《数据结构》4皇后问题的Haskell程序建模

《数据结构》书中通过构造树的方式来产生集合的所有子集。在这个内容之后,书上提到了通过构造树来解决4皇后问题。今天尝试用Haskell来实现,只需要很短的程序,就可以把问题解决。如果是C语言,会麻烦很多。

程序代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
module Main
    where
-- 严蔚民、吴伟民:《数据结构》(第二版)清华大学出版社 Page 149
-- 4皇后问题建模

level::Int -> [(Int, Int)]
level n = [(n,x) | x <- [0..3]]

listlevel :: Int -> [[(Int, Int)]]
listlevel n = [[(n,x)] | x <- [0..3]]

-- collision : 2 point has collision
collision :: (Int, Int) -> (Int, Int) -> Bool
collision (x,y) (i,j) = x == i || y == j || x-i == y-j || x-i == j-y

validexpand x [] = True
validexpand x (y:ys) = not (collision x y) && (validexpand x ys)

expand :: [(Int, Int)] -> [[(Int, Int)]] -> [[(Int,Int)]]
-- if there is one param being empty list, the answer is empty list
expand [] _ = [] 
expand _ [] = []
expand (x:xs) [y]   -- 2nd param has single element
    | (validexpand x y) = reverse (x:y) : (expand xs [y])
    | otherwise = (expand xs [y])
expand xs (y:ys) = (expand xs [y]) ++ (expand xs ys)

pool:: Int -> [ [(Int, Int)] ]
pool 0 = listlevel 0
pool n = expand (level n) (pool (n-1))

queue4 = pool 3

main = putStrLn $ show queue4

说明:

关键在于expand函数,其目的是将树的深度加1,通过validexpand函数去掉不满足皇后互不相吃规则的叶子。每次expand之后,只保留满足条件的叶子结点,构成新一级。

4皇后,树的深度是4(0,1,2,3 ).

此程序很容易扩展为N皇后问题。