[此帖子收录不佳,因此我进行了一些建议的修改,以期使其后代得到改善。我希望它对以后发现它的人有所帮助!]
我一直在尝试使用一个简单的Sudoku示例来理解递归/回溯/ DFS。我对Sudoku示例本身并不真正感兴趣,因此,根据建议,我将下面的示例最小化为2x2数独板,以便仅关注使我困惑于递归的问题(感谢@MisterMiyagi的建议)。
在下面的代码中,我有一个辅助函数check_board,该函数采用2x2矩阵并检查其行和列中是否有任何数字重复(即,检查输入的2x2数独是否有效)。然后,该函数solve_sudoku被我理解为解决数独问题的标准DFS /回溯算法,方法是选择第一个空位置(用0表示),然后在其中尝试值1和2,然后递归寻找解决方案。
所以输入[[0,0], [0,2]]应该是输出[[[2,1],[1,2]],但是我正在接收输出False。
@ThierryLathuille helped by noticing the problem in the code: after trying each possible descendant node (in this case, by trying both values 1, 2), I missed the "backtracking" step, and need to add a line resetting the value to 0, meaning that square in the matrix would be stuck in a 2 for all subsequent calls (or, in the original 9x9 example, stuck at a 9):
When you see that the last value you tried in a square can't lead to a valid solution, you try the next one, until you reach 9. At this point, you return and go back to incrementing the value in the previous square, but you current one still contains the value 9, so it is considered as non available for the next attempts.
You just have to put it back to its original value of 0 before returning:
Now here's where I'm still confused and the point of the question: I am trying to think about the recursion like a tree. Once one of the nodes has tried every value for a square and its descendant nodes have all come back False, doesn't it just report False back up to its parent? Why would anyone else look at that board with the 2 again?
If you can help with my understanding of recursion, I'd really appreciate it!
Edit: @ThierryLathuille answered the question again in a comment! Thanks so much!
Note that when calling your function recursively, you don't pass copies of the board, but only manipulate the same board everywhere. As your code worked, each time you explored a branch of the tree, all the squares you touched during the exploration were left with a non-zero value, so they were not considered as free any more.
I had the mistaken idea that whenever a function is called in recursion, it gets a new copy of all its variables to act on. Which of course it does, but not of the input! Another fix to the code would be to use Python's copy module with the line copy_board = copy.deepcopy(board) and operate on and return copy_board at each instantiation of the function, which is what I mistakenly thought Python always did in recursion.
也许这与按值传递与按引用传递有关,而Python总是按引用传递?对此主题的任何其他讨论仍将不胜感激!
这是用行将其注释掉的破断代码:
def check_board(board: list):
for i in chars:
for j in chars:
for k in chars:
if k == j:
continue
if board[i][j] == board[i][k] and board[i][j] != 0:
return False
if board[j][i] == board[k][i] and board[j][i] != 0:
return False
return True
def solve_sudoku(board: list):
chars = range(2)
if not check_board(board):
return False
for i in chars:
for j in chars:
if board[i][j] == 0:
for a in chars:
board[i][j] = a+1
if solve_sudoku(board):
return solve_sudoku(board)
# uncommenting this next line fixes the algorithm
#board[i][j] = 0
return False
return board
board = [[0,0],[0,2]]
if __name__ == "__main__":
print(solve_sudoku(board))
输出:False