我试图在Haskell中构建一个回溯数据求解器。但我还是坚持了最后一点。我创建了一个名为nextBoards的函数,它返回所有可能的soduko板,其中下一个空位用可能的值填充。现在我试图在Haskell中使用回溯,但我不能使用像while循环这样的东西,现在我真的很困惑如何做到这一点。我之前在Java中做过一个数独求解器,但我现在完全不知道如何在Haskell中做到这一点。
-- Generate the next boards for a given board
nextBoards :: Board -> [Board]
nextBoards b =
let position = findFirstEmpty b
in [update z (snd position) (fst position) b | z <- options b (snd position) (fst position)]
-- We found the real solution
solve :: Board -> [Board] -> Board
solve focus options
| not (notEmpty focus) = focus
-- We hit a dead path try the next option
solve focus options
| solve (head options) (tail options)
-- We are solving the focus, generate the next boards
-- and save the rest in the options
solve focus options
| solve (head (nextBoards focus)) (tail (nextBoards focus))
我真的不知道如何继续。
答案 0 :(得分:0)
您可以在(部分)解决方案空间(例如所有可能的Board
s)S
上实现回溯解决方案,其类型签名如下:
backtrack :: S -> [S]
S
当前状态,[S]
所有有效电路板列表。现在通常有三种可能的选择:
我们找到了一个solved
的状态,我们返回一个包含我们解决方案的列表( singleton ):
backtrack s | solved s = [s]
我们找到了一条死路,在这种情况下我们不再付出努力,并返回一个空列表:
| invalid s = []
或者我们可能需要进一步部署我们的解决方案,我们生成children
:从s
前进一步的状态,并递归调用回溯,我们返回{{1这些孩子的所有concat
:
backtrack
或者把它们放在一起:
| otherwise = concatMap backtrack $ children s
只需为backtrack :: S -> [S]
backtrack s | solved s = [s]
| invalid s = []
| otherwise = concatMap backtrack $ children s
状态生成invalid
的空列表(正如您的解决方案可能做的那样),或者通过阻止生成无效{{1},可以省略children
保护}}第
现在为您的问题奠定基础,生成invalid
将归结为您的Board
功能:
children
或稍微美化你的功能:
nextBoards
现在,solve(或children = nextBoards
)方法定义为:
children :: Board -> [Board]
children s = [update s y x v | v <- options s y x]
where (x,y) = findFirstEmpty s
backtrack
将生成一个所有有效解决的Sudoku主板的列表(最初填充的地方,仍然填写)。该列表是懒惰生成的,因此如果您想要一个有效的解决方案,则只需使用backtrack :: Board -> [Board]
backtrack s | not (notEmpty s) = [s]
| otherwise = concatMap backtrack $ children s
:
backtrack