【发布时间】:2019-03-01 20:25:51
【问题描述】:
刚从一些python代码开始,我试图使用here发布的回溯算法制作数独求解器
所以我现在有这个:
SUDOKU= [[0, 6, 0, 1, 0, 4, 0, 5, 0],
[0, 0, 8, 3, 0, 5, 6, 0, 0],
[2, 0, 0, 0, 0, 0, 0, 0, 1],
[8, 0, 0, 4, 0, 7, 0, 0, 6],
[0, 0, 6, 0, 0, 0, 3, 0, 0],
[7, 0, 0, 9, 0, 1, 0, 0, 4],
[5, 0, 0, 0, 0, 0, 0, 0, 2],
[0, 0, 7, 2, 0, 6, 9, 0, 9],
[0, 4, 0, 5, 0, 8, 2, 7, 0]]
sublist = []
def validate(value, y, x, sudoku):
# check linea
for idx in range(0,9):
if sudoku[y][idx] == value:
return False
for idy in range(0, 9):
if sudoku[idy][x] == value:
return False
return True
def validate_square(value, y, x, sudoku):
if y < 3 and x < 3:
aux_list = [aux_list[0:3] for aux_list in sudoku[0:3]]
if value in [j for i in aux_list for j in i]:
return False
else:
return True
elif y < 3 and (x >= 3 and x < 6):
aux_list = [aux_list[3:6] for aux_list in sudoku[0:3]]
if value in [j for i in aux_list for j in i]:
return False
else:
return True
elif y < 3 and (x >= 6 and x < 9):
aux_list = [aux_list[6:9] for aux_list in sudoku[0:3]]
if value in [j for i in aux_list for j in i]:
return False
else:
return True
elif (y >= 3 and y < 6) and x < 3:
aux_list = [aux_list[0:3] for aux_list in sudoku[3:6]]
if value in [j for i in aux_list for j in i]:
return False
else:
return True
elif (y >= 3 and y < 6) and (x >= 3 and x < 6):
aux_list = [aux_list[3:6] for aux_list in sudoku[3:6]]
if value in [j for i in aux_list for j in i]:
return False
else:
return True
elif (y >= 3 and y <6) and (x >= 6 and x < 9):
aux_list = [aux_list[6:9] for aux_list in sudoku[3:6]]
if value in [j for i in aux_list for j in i]:
return False
else:
return True
elif (y >= 6 and y < 9) and x < 3:
aux_list = [aux_list[0:3] for aux_list in sudoku[6:9]]
if value in [j for i in aux_list for j in i]:
return False
else:
return True
elif (y >= 6 and y < 9) and (x >= 3 and x < 6):
aux_list = [aux_list[3:6] for aux_list in sudoku[6:9]]
if value in [j for i in aux_list for j in i]:
return False
else:
return True
elif (y >= 6 and y < 9) and (x >= 6 and x < 9):
aux_list = [aux_list[6:9] for aux_list in sudoku[6:9]]
if value in [j for i in aux_list for j in i]:
return False
else:
return True
else:
return True
def auto_complete(sudoku):
for idy in range(0,9):
for idx in range(0,9):
if sudoku[idy][idx] == 0:
for attempt in range(1, 10):
if validate(attempt, idy, idx, sudoku) == True and validate_square(attempt, idy, idx, sudoku) == True:
sudoku[idy][idx] = attempt
if __name__ == "__main__":
auto_complete(SUDOKU)
for i in SUDOKU:
print(i)
这是我得到的解决方案:
[9, 6, 3, 1, 8, 4, 7, 5, 0]
[4, 7, 8, 3, 9, 5, 6, 2, 0]
[2, 5, 0, 7, 6, 0, 8, 9, 1]
[8, 9, 5, 4, 3, 7, 1, 0, 6]
[1, 2, 6, 8, 5, 0, 3, 0, 7]
[7, 3, 0, 9, 2, 1, 5, 8, 4]
[5, 8, 9, 0, 7, 3, 4, 6, 2]
[3, 1, 7, 2, 4, 6, 9, 0, 9]
[6, 4, 0, 5, 1, 8, 2, 7, 3]
这是预期的一个(正确的解决方案): sudoku
此时我有一个算法可以部分回溯,但是当涉及到一个不适合其单元格(行、行、方形违规)的值时,它只会将其留空,从*帖子我知道我应该去向后的位置(可能是从 idx 中减去 1?)将 1 添加到该单元格并重新验证该值。
我很迷茫,所以关于如何以 Python 方式改进此代码的任何建议?
另外,列表列表是构建数独数据的最佳方式吗?它们的工作方式似乎与数组有点不同(这是我来自的地方,反正不是专家)
感谢大家的阅读!
【问题讨论】:
-
我看起来不像你的
auto_complete函数做*中描述的回溯,如果我理解正确的话,因为如果一个单元格不能被验证,你必须后退,你在这里不这样做。所以要从一个单元格导航到另一个单元格,我会做一个 while 循环,如果一个单元格无法验证,我会减少 idx 或 idy。 -
回溯算法是一种广度优先搜索算法,这意味着它在技术上创建一个树/图数据结构,因为它填充每个正方形。当 a 出现错误值时,它会跳回到树中最正确的最低点。可以在方形背面或多行背面。您可能必须存储所有以前访问过的棋盘状态才能知道要回溯多远。等离子方法也可以。时间复杂度更差,但更容易编码。如果将它们插入到树结构中,则还必须制作树。
-
我想了想,这可能是我尝试解决这个问题的方式,但是,在嵌套的 for 循环中运行一段时间的性能如何?我的意思是,情况并非如此,因为两个 fors 都很小,但这是一个好的做法还是建议从其他方式接近?
-
另外,在您的代码中,您选择就地修改数独。如果这样做,在回溯时,您必须小心不要更改在数独开始时设置的值。
-
norvig.com/sudoku.html 这可能会有所帮助。他概述了一个关于编程蛮力解决方案的从头到尾的教程
标签: python backtracking sudoku