我在网上搜索了不同的方案来解决Haskell中的n-皇后问题,但是没有找到任何一种可以在O(1)时间内检查不安全位置的解决方案,就像你保留一个数组来存储/对角线和一个数组来存储\对角线的那个方案。
我发现大多数解决方案只是将每个新皇后与之前的所有皇后进行比较。类似于这样的方式: http://www.reddit.com/r/programming/comments/62j4m/nqueens_in_haskell/
nqueens :: Int -> [[(Int,Int)]]
nqueens n = foldr qu [[]] [1..n]
where qu k qss = [ ((j,k):qs) | qs <- qss, j <- [1..n], all (safe (j,k)) qs ]
safe (j,k) (l,m) = j /= l && k /= m && abs (j-l) /= abs (k-m)
如何在Haskell中实现这样的“O(1)方法”呢?我不想要任何“超级优化”的东西。只是以函数式方式生成“这个对角线已经被使用了吗?”数组的一些方法。更新:感谢大家的回答!我最初提出这个问题的原因是想解决一个更难的回溯问题。我知道如何在命令式语言中解决它,但无法立即想到一个纯函数数据结构来完成工作。我觉得皇后问题将是一个很好的模型(是回溯问题 :))来解决整个数据结构问题,但这并不是我的真正问题。
我实际上想找到一种数据结构,它允许O(1)随机访问,并保存值,这些值要么处于“初始”状态(自由行/对角线,在n皇后情况下),要么处于“最终”状态(占用行/对角线),转换(自由至占用)为O(1)。这可以在命令式语言中使用可变数组实现,但我觉得更新值的限制只允许一个良好的纯函数数据结构(与快速排序不同,例如,它真的希望可变数组)。
我认为sths的解决方案是利用Haskell中的不可变数组所能达到的最好的状态,“主要”函数看起来就像我想要的:
-- try all positions for a queen in row n-1
place :: BoardState -> Int -> [[(Int, Int)]]
place _ 0 = [[]]
place b n = concatMap place_ (freefields b (n-1))
where place_ p = map (p:) (place (occupy b p) (n-1))
主要问题似乎在于找到更好的数据结构, 因为 Haskell 数组具有 O(n) 的更新时间。
其他不错的建议都无法达到 O(1) 的神话标准:- DiffArrays 接近但在回溯时会出现问题。它们实际上变得超级慢 :( - STUArrays 与漂亮的函数式回溯方法相冲突,所以被舍弃了。 - 映射和集合只有 O(log n) 的更新时间。
我并不确定是否存在全局解决方案,但这似乎是一个有前途的方向。 更新: 我找到的最有希望的数据结构是 Trailer Arrays。基本上是一个 Haskell DiffArray,但在回溯时它会恢复原样。