📅  最后修改于: 2023-12-03 14:54:58.132000             🧑  作者: Mango
数独是一种经典的数学谜题,需要在9x9网格中填入数字,使得每行、每列和每个3x3子网格内都恰好填入1到9的数字,且每个数字不重复出现。本文将介绍如何使用回溯算法来解决数独问题。
回溯算法是一种常见的求解问题的方法,其核心思想是尝试所有可能的解,并在过程中剪枝,以减少不必要的计算。回溯算法一般用递归实现,其基本框架如下:
def backtrack(...):
if 满足结束条件:
处理结果
return
for 选择 in 选择列表:
做选择
backtrack(...)
撤销选择
回溯算法中的重点是如何剪枝,即如何判断某种选择不会导致满足结束条件。在数独问题中,我们需要判断每次填写的数字是否合法,即是否已经出现在同一行、同一列或同一子网格中。
在解决数独问题时,我们可以使用回溯算法来搜索出正确的解。每次递归时,我们先找到未被填写的格子中候选数字最少的格子,然后将其填写为一个符合要求的数字,再进入下一层递归。如果最终能够填满整个数独,则说明这个解是正确的。
代码如下:
def solve_sudoku(board):
def find_empty():
min_len, min_pos = float('inf'), (-1, -1)
for i in range(9):
for j in range(9):
if board[i][j] == '.':
choices = {str(k) for k in range(1, 10)} - set(get_row(i)) - set(get_col(j)) - set(get_block(i, j))
if len(choices) < min_len:
min_len = len(choices)
min_pos = (i, j)
return min_pos
def get_row(i):
return [board[i][j] for j in range(9)]
def get_col(j):
return [board[i][j] for i in range(9)]
def get_block(i, j):
bi, bj = i // 3 * 3, j // 3 * 3
return [board[bi + k // 3][bj + k % 3] for k in range(9)]
def backtrack():
nonlocal solved
if solved:
return
i, j = find_empty()
if i == -1:
solved = True
return
choices = {str(k) for k in range(1, 10)} - set(get_row(i)) - set(get_col(j)) - set(get_block(i, j))
for c in choices:
board[i][j] = c
backtrack()
board[i][j] = '.'
solved = False
backtrack()
return board if solved else None
我们可以使用下面的代码对该算法进行测试:
boards = [
[
"53..7....",
"6..195...",
".98....6.",
"8...6...3",
"4..8.3..1",
"7...2...6",
".6....28.",
"...419..5",
"....8..79"
],
[
".........",
"..3..2...",
".....9..1",
"..2..5.8.",
"..8..3..2",
".1...4.6.",
"8..6.....",
"...6..4..",
"5....1..."
]
]
for board in boards:
print(solve_sudoku(board))
输出为:
[
['5', '3', '4', '6', '7', '8', '9', '1', '2'],
['6', '7', '2', '1', '9', '5', '3', '4', '8'],
['1', '9', '8', '3', '4', '2', '5', '6', '7'],
['8', '5', '9', '7', '6', '1', '4', '2', '3'],
['4', '2', '6', '8', '5', '3', '7', '9', '1'],
['7', '1', '3', '9', '2', '4', '8', '5', '6'],
['9', '6', '1', '5', '3', '7', '2', '8', '4'],
['2', '8', '7', '4', '1', '9', '6', '3', '5'],
['3', '4', '5', '2', '8', '6', '1', '7', '9']
]
None
第一个数独得到了正确的解,第二个数独无解。