Python 为什么我的回溯算法不起作用,并产生重复条目的方块?
嗨,我正在尝试使用回溯来解决一个问题 我编写了一个函数来返回一个空值(如果存在),这里0表示一个空值。另一个测试将数字放置在棋盘中特定位置是否有效(基于数独规则)的函数,以及另一个实现回溯以实际解决谜题的函数 当我运行算法时,提供了电路板,我得到:Python 为什么我的回溯算法不起作用,并产生重复条目的方块?,python,python-3.x,algorithm,recursion,backtracking,Python,Python 3.x,Algorithm,Recursion,Backtracking,嗨,我正在尝试使用回溯来解决一个问题 我编写了一个函数来返回一个空值(如果存在),这里0表示一个空值。另一个测试将数字放置在棋盘中特定位置是否有效(基于数独规则)的函数,以及另一个实现回溯以实际解决谜题的函数 当我运行算法时,提供了电路板,我得到: [[2, 1, 3, 7, 4, 5, 6, 8, 9], [1, 3, 4, 2, 5, 6, 8, 9, 7], [5, 6, 9, 4, 3, 8, 2, 7, 1], [7, 5, 8, 1, 2, 4, 9, 3, 6], [4,
[[2, 1, 3, 7, 4, 5, 6, 8, 9],
[1, 3, 4, 2, 5, 6, 8, 9, 7],
[5, 6, 9, 4, 3, 8, 2, 7, 1],
[7, 5, 8, 1, 2, 4, 9, 3, 6],
[4, 8, 7, 5, 6, 9, 1, 2, 3],
[3, 2, 5, 6, 9, 7, 4, 1, 8],
[9, 7, 6, 3, 8, 1, 5, 4, 2],
[6, 9, 2, 8, 1, 3, 7, 5, 4],
[8, 4, 1, 9, 7, 2, 3, 6, 5]]
它似乎是在逐列逐行的基础上工作的。但是3x3
方块不正确
例如,以左上角的正方形为例
[[2, 1, 3],
[1, 3, 4],
[5, 6, 9]]
这包含重复的条目,例如3
,并且每个编号1-9
也不包含一次
根据我的可行性移动
方法,这是不允许的
很明显,我犯了一个错误,但我不知道在哪里
有什么想法吗 原因是
可行性移动的这一部分有错误:
row = coordinate[0] // 3
col = coordinate[1] // 3
for i in range(x * 3, x * 3 + 3):
for j in range(y * 3, y * 3 + 3):
if board[row][col] == number and (i, j) != coordinate:
return False
迭代应基于行
和列
,而不是基于x
和y
。当您从board
读取值时,应使用i
和j
作为索引。现在,你看了9次板上的同一个单元格
row = (x // 3) * 3
col = (y // 3) * 3
for i in range(row, row + 3):
for j in range(col, col + 3):
if board[i][j] == number and (i, j) != coordinate:
return False
但是,您的算法太慢,无法在合理的时间内解决此难题。您应该通过以下几点改进算法:
- 不要实时查找空白单元格。相反,将它们收集到队列中,然后从队列中弹出(回溯时将它们放回原处)
- 不要检查某个值是否对某个单元格有效,而是保持领先一步,跟踪每个单元格中哪些值仍然有效(在
集合中)。在算法一开始就初始化它
- 放置值时,更新受影响的单元格集
最后两点似乎没有什么好处,因为它只是将扫描行、列和框的工作转移到算法中的另一个时刻,但好处在于:
- 为了使递归树保持狭窄,请优先考虑具有尽可能少的值的单元格,理想情况下只有一个值。为此,可以使用python的
heapq
,它应该应用于我在第一点中提到的队列
我把实现留给你,因为这不是你的问题。不管怎样,网上有很多实用的例子。这是一个很好的答案,谢谢。关于这些技术的改进,我以前从未听说过。你能提供一个开始学习的地方吗?你推荐吗?我建议你只编写很多程序,也许在提供代码挑战的网站上。选择一个你自己解决后可以看到其他解决方案的地方;并向他们学习。对于数独,我并没有真正找到我所描述的,但看起来是一个很好的方法。
row = (x // 3) * 3
col = (y // 3) * 3
for i in range(row, row + 3):
for j in range(col, col + 3):
if board[i][j] == number and (i, j) != coordinate:
return False