我将如何在这里实现回溯?
Posted
技术标签:
【中文标题】我将如何在这里实现回溯?【英文标题】:How would I implement backtracking here? 【发布时间】:2021-04-03 17:01:13 【问题描述】:我一直在努力为我的数独求解器找到正确的逻辑。到目前为止,我已经创建了一个函数来获取 (x,y) 坐标和数字并检查它是否合法。
虽然我不明白如何遍历网格,将每个 0 替换为合法数字,然后返回并修复导致解不正确的数字。
例如,有时我会在网格上留下 0,因为某些数字无法再播放。我深入研究了一下,发现之前在同一行播放的数字是合法的 但破坏了这个谜题。相反,如果这些数字再高一点,难题就会得到解决。
我知道 backtracking 会是我的朋友,但是我不知道如何实现它。到目前为止,这就是我所拥有的。
solve.py
import numpy as np
import time
class sodoku:
def __init__(self,grid,boxRange):
self.grid = grid
self.boxRange = boxRange
def show(self):
for row in self.grid:
print(row)
def solve(self):
def possible(num,x,y):
def box(x,y):
board = np.array(self.grid)
result =
size = 3
for i in range(len(board) // size):
for j in range(len(board) // size):
values = board[j * size:(j + 1) * size, i * size:(i + 1) * size]
result[i * size + j + 1] = values.flatten()
if y <= 2 and x <= 2:
squareBox = result[1]
if (y <= 5 and y > 2) and x <= 2:
squareBox = result[2]
if (y <= 8 and y > 5) and x <= 2:
squareBox = result[3]
if (y <= 2 ) and (x <= 5 and x > 2):
squareBox = result[4]
if (y <= 5 and y > 2)and (x <= 5 and x > 2):
squareBox = result[5]
if (y <= 8 and y > 5)and (x <= 5 and x > 2):
squareBox = result[6]
if (y <= 2) and (x <= 8 and x > 5):
squareBox = result[7]
if (y <= 5 and y > 2)and (x <= 8 and x > 5):
squareBox = result[8]
if (y <= 8 and y > 5)and (x <= 8 and x > 5):
squareBox = result[9]
return squareBox
row = self.grid[y]
column= [r[x] for r in self.grid]
square = box(x,y)
if (num not in row) and (num not in column) and (num not in square):
return True
else:
return False
y = 0
for row in self.grid:
x = 0
for number in row:
if number == 0:
for i in range(1,10):
if possible(i,x,y):
row[x] = i
elif i == 9 and possible(i,x,y) == False: pass
#what would I do here now
x += 1
y += 1
boxRange = "3x3"
bxd = []
with open('board.txt', 'r') as f:
for line in f:
line = line.strip()
line = line.split(' ')
bLine = [int(x) for x in line]
bxd.append(bLine)
# brd = [[3,0,0,2],[0,4,1,0],[0,3,2,0],[4,0,0,1]]
brd = sodoku(bxd,boxRange)
brd.show()
brd.solve()
print('-----Solved------')
brd.show()
board.txt
5 3 0 0 7 0 1 0 0
6 0 0 1 9 5 0 0 0
0 9 8 0 0 0 0 6 0
8 0 0 0 6 0 0 0 3
4 0 0 8 0 3 0 0 1
7 0 0 0 2 0 0 0 6
0 6 0 0 0 0 2 8 0
0 0 0 4 1 9 0 0 5
0 0 0 0 8 0 0 7 9
【问题讨论】:
NameError:未定义名称“索引”。您可以尝试将用于每次移动的板保存到数组中。因此,如果您想要返回,只需在您想要的步骤中获取电路板并从中重新处理。 你能试着把这个想法变成代码吗?我无法理解你在说什么。 【参考方案1】:递归伪代码回溯数独求解器:
#solve will return a solved board, or None if it fails
def solve(board):
#case 1: board is solved
if board.is_solved: #simple check for leftover empty spaces
return board #board is solved. unzip the call stack
pos = board.next_empty_space()
valid = [i for i in range(1,10) if board.is_valid(pos, i)]
#case 2: not solved and no more valid moves
if not valid:
return None #no valid moves left
new_board = copy(board) #don't step on the original data in case this isn't the solution
for value in valid:
new_board[pos] = value
result = solve(new_board)
#case 3: one of the valid moves led to a valid solution
if result is not None: #we found a fully solved board
return result #here's where we unzip the call stack
#case 4: none of the valid moves led to a valid solution
return None #none of the valid moves panned out
基本上,您将板上的每个空白空间视为树中的一个分支,并从每个分支的子分支中插入一个当前在树中该点有效的新数字。如果您到达一个分支的末尾,并且没有更多有效的移动(子分支),那么您要么成功填写了所有空格,要么其中一个数字是错误的。当None
被返回,并且执行返回给调用者(调用堆栈中的上一帧),for
循环中的本地位置遍历有效移动就是“记住”你所在的位置,以及下一个可能的有效举动应该是。它基本上是一种用于正确棋盘状态的深度优先树搜索算法。
【讨论】:
EDIT 你必须小心这里的可变类型,并复制电路板以发送到递归函数,否则你可能会弄乱电路板状态以备将来调用的功能。以上是关于我将如何在这里实现回溯?的主要内容,如果未能解决你的问题,请参考以下文章