Haskell解决八皇后问题的3种解法代码


八皇后问题是经典的问题,有很多的算法,用Haskell来解决,很有意思,值得仔细研究。这些算法都来自于互联网。

 

解法1:

safe :: Int -> [Int] -> Int -> Bool
safe _ [] _ = True
safe x (x1:xs) n = 
 x /= x1 && x /= x1 + n && x /= x1 - n && safe x xs (n+1)

queens :: Int -> [[Int]]
queens 0 = [[]]
queens n = [ x:y | y <- queens (n-1), x <- [1..8], safe x y 1]


解法2,

import Control.Monad
import Data.List
 
-- given n, "queens n" solves the n-queens problem, returning a list of all the
-- safe arrangements. each solution is a list of the columns where the queens are
-- located for each row
queens :: Int -> [[Int]]
queens n = map fst $ foldM oneMoreQueen ([],[1..n]) [1..n] where 
 
 -- foldM :: (Monad m) => (a -> b -> m a) -> a -> [b] -> m a
 -- foldM folds (from left to right) in the list monad, which is convenient for 
 -- "nondeterminstically" finding "all possible solutions" of something. the 
 -- initial value [] corresponds to the only safe arrangement of queens in 0 rows
 
 -- given a safe arrangement y of queens in the first i rows, and a list of 
 -- possible choices, "oneMoreQueen y _" returns a list of all the safe 
 -- arrangements of queens in the first (i+1) rows along with remaining choices 
 oneMoreQueen (y,d) _ = [(x:y, delete x d) | x <- d, safe x] where
 
 -- "safe x" tests whether a queen at column x is safe from previous queens
 safe x = and [x /= c + n && x /= c - n | (n,c) <- zip [1..] y]
 
-- prints what the board looks like for a solution; with an extra newline
printSolution y = do
 let n = length y
 mapM_ (\x -> putStrLn [if z == x then 'Q' else '.' | z <- [1..n]]) y
 putStrLn ""
 
-- prints all the solutions for 6 queens
main = mapM_ printSolution $ queens 6


解法3,基于fold

import Data.List (transpose, intercalate)
 
queenPuzzle :: Int -> Int -> [[Int]]
queenPuzzle nRows nCols
 | nRows <= 0 = [[]]
 | otherwise =
 foldr
 (solution a ->
 a ++
 foldr
 (iCol b ->
 if safe (nRows - 1) iCol solution
 then b ++ [solution ++ [iCol]]
 else b)
 []
 [1 .. nCols])
 []
 (queenPuzzle (nRows - 1) nCols)
 where
 safe iRow iCol solution =
 True `notElem`
 zipWith
 (sc sr ->
 (iCol == sc) || (sc + sr == iCol + iRow) || (sc - sr == iCol - iRow))
 solution
 [0 .. iRow - 1]
 
-- TEST ------------------------------------------------------------------------
-- 10 columns of solutions for the 7*7 board:
showSolutions :: Int -> Int -> [String]
showSolutions nCols nBoardSize =
 unlines <$>
 (((intercalate " " <$>) . transpose . (boardLines <$>)) <$>
 chunksOf nCols (queenPuzzle nBoardSize nBoardSize))
 where
 boardLines rows =
 (
 ->
 foldMap
 (c ->
 [ if r == c
 then '♛'
 else '.'
 ])
 [1 .. (length rows)]) <$>
 rows
 
chunksOf :: Int -> [a] -> [[a]]
chunksOf i xs = take i <$> ($ (:)) (splits xs) []
 where
 splits [] _ n = []
 splits l c n = l `c` splits (drop i l) c n
 
main :: IO ()
main = (putStrLn . unlines) $ showSolutions 10 7

 

你可能感兴趣的:(FP,Haskell)