此功能未终止!我试图在一个八乘八棋盘上为八个皇后生成所有可能的安全组合。我不确定出了什么问题。我的代码如下。该板表示为[x1,x2 ... x8],其中值xi是列,所述值的索引是行。
safeH函数应该创建八个数字的所有组合而不重复,例如[1,4,3,5,8,6,7,2],[6,4,8,2,5,1,3 ,7]等等......
safeD函数会将第一个元素与所有后继元素进行比较,以确保没有女王放置在此女王的对角线上(此元素)等等。
queens = [ [x1,x2,x3,x4,x5,x6,x7,x8] | x1 <- [1..8], x2 <- [1..8]
, x3 <- [1..8], x4 <- [1..8]
, x5 <- [1..8], x6 <- [1..8]
, x7 <- [1..8], x8 <- [1..8]
, safeH [x2,x3,x4,x5,x6,x7,x8] x1
, safeD [x2,x3,x4,x5,x6,x7,x8] x1
[x1,x2,x3,x4,x5,x6,x7,x8] 1 ]
safeH l e =
if elem e l then False
else if length (l)/=0 then safeH(tail l)(head l)
else True
safeD l e xs n =
if last xs /= e then
if length l /= 0 then
if head l + n == e || head l - n == e then False
else safeD (tail l) e xs (n + 1)
else safeD (tail xs) (head xs) xs 1
else True
答案 0 :(得分:3)
为了计算queens
,必须迭代8 ^ 8 = 16777216个案例,每个案例都将受safeH
和safeD
的约束。这需要一段时间。
queens = [ [x1,x2,x3,x4,x5,x6,x7,x8] | x1 <- [1..8], x2 <- [1..8]
, x3 <- [1..8], x4 <- [1..8]
, x5 <- [1..8], x6 <- [1..8]
, x7 <- [1..8], x8 <- [1..8]
您可以了解其他人如何解决the 8-queens problem in Haskell。
答案 1 :(得分:3)
根据对Simon的回答的评论,而不是修复你的代码,我会逐步完成自己的代码。我希望你能更好地理解问题并更好地理解Haskell。显然,如果这是作业,你不应该提交我的代码。
公平警告 - 我对Haskell也很新,所以我对花生画廊的任何建议持开放态度!
import Data.List
{- myNQueens n will solve the n-queens problem for the given board-size nxn
for n queens. Each board is represented by [x1, x2..xn] where the index
represents the column and the value of xi represents the row. -}
--type: this function takes an Int and returns a list of lists of Ints.
myNQueens :: Int -> [[Int]]
-- here is a list comprehension that does away with your safeH function.
-- it checks all permutations of the numbers [1..n] to see if they represent
-- a legal board. As you'll see, queensSafe only checks diagonals. Horizontals
-- do not need to be checked because generating the permutations already takes
-- care of that. If you'd prefer not to use Data.List.permutations, it shouldn't
-- be too hard to hand-roll your own.
myNQueens n = [x | x <- permutations [1..n], queensSafe x]
--type: from list of Ints to bool. Returns True if legal board, else False.
queensSafe :: [Int] -> Bool
-- queensSafe is a recursive function that checks if the queen in the first column
-- can be captured. If so, it returns false. If not, it is called again with the board
-- without the first column.
-- base case: the empty board is safe
queensSafe [] = True
-- l@(x:xs) is just pattern matching. x is the first element of the
-- list, xs is the remaining elements, and l is just syntactic sugar for
-- referencing the whole list.
queensSafe l@(x:xs)
-- these "guards" are basically if-else statements.
-- if firstQueenSafe l == True then queensSafe x:xs = queensSafe xs. else, False.
| firstQueenSafe l == True = queensSafe xs
| otherwise = False
firstQueenSafe :: [Int] -> Bool
firstQueenSafe l@(x:xs) =
-- unsafe1 generates a list of all of the unsafe diagonals down and to the right.
-- unsafe2 generates a list of all of the unsafe diagonals up and to the left.
let unsafe1 = [x, x - 1 .. x - length l]
unsafe2 = [x, x + 1 .. x + length l]
-- zipped just pairs unsafe1 and unsafe2 with copies of the actual board
-- (except the first element.) If any of tuples contain 2 of the same values,
-- then the board is unsafe.
zipped = zip (tail unsafe1) (tail l) ++ zip (tail unsafe2) (tail l)
-- countMatches just checks if there are any matches in zipped.
countMatches = length [x | x <- zipped, fst x == snd x]
in if countMatches == 0 then True else False
显然,这不是最优的,但我认为非常清楚。还有一小段代码!只是为了证明它有效:
*Main> head $ myNQueens 8
[6,4,7,1,3,5,2,8]
*Main> head $ myNQueens 9
[6,3,5,8,1,4,2,7,9]
*Main> head $ myNQueens 10
[7,5,8,2,9,3,6,4,1,10]
*Main> length $ myNQueens 8 -- runs in about a second
92
*Main> length $ myNQueens 9 -- runs in about 20 seconds
352
*Main> length $ myNQueens 10 -- runs in a couple of minutes
724
Learn You a Haskell和Real World Haskell都是非常好的资源。我还在99 Haskell Problems工作,这是我最初看到这个问题的地方。如果你想看到一些解决其他一些问题的简单代码,(我不是真的想要优化,只是简单易读的代码,这样我就可以学习)你可以分叉https://github.com/ostrowr/99-Haskell-Problems