def answer_solve_sudoku(__grid):
res = check_sudoku(__grid)
if res is None or res is False:
return res
grid = copy.deepcopy(__grid)
# find the first 0 element and change it to each of 1..9,
# recursively calling this function on the result
for row in xrange(9):
for col in xrange(9):
if grid[row][col] == 0:
for n in xrange(1, 10):
grid[row][col] = n
new = answer_solve_sudoku(grid)
if new is not False:
return new
# backtrack
return False
# if we get here, we found no zeros and so we're finished
return grid
以下是代码,如果网格是有效的数据,check_sudoku(grid)
可以返回。
我只是无法理解递归部分,我试图在纸上写下这个过程,但每次都失败了,回复是怎么回事?什么是new
?如果answer_solve_sudoku(grid)
有效?
我知道它设置每0到1..9,并检查它是否是有效的网格,但我无法在纸上绘制整个过程。并且无法真正理解回溯是如何工作的。
顺便说一句,有什么建议可以理解递归代码吗?最诚挚的问候,
盛云
修改
我一遍又一遍地阅读代码,现在我有了一些了解,但我对此并不确定,如果有人给我一些评论,那将会很友好。
1,只有当求解器找到解决方案时才会调用return new
,这将在return grid
2,何时
# backtrack
return False
被叫?如果下一个解决方案不正确,check_sudoku(__grid)
将返回False
,如果下一个解决方案是正确的,它将调用另一个answer_solve_sudoku(grid)
,直到它获得正确的解决方案,并且当它获得时正确的解决方案,它将return grid
然后return new
。所以什么时候:
# backtrack
return False
称为?
答案 0 :(得分:1)
我没有把它写在纸上,而是提出了更好的建议。格式化代码以向您显示逻辑正在执行的操作。这是一种方法:
def print_counter(val, msg):
print "%s[%d] %s" % (" "*val, val, msg)
def answer_solve_sudoku(__grid, counter=0):
res = check_sudoku(__grid)
if res is None or res is False:
return res
grid = copy.deepcopy(__grid)
for row in xrange(9):
for col in xrange(9):
if grid[row][col] == 0:
for n in xrange(1, 10):
grid[row][col] = n
print_counter(counter,"test: (row %d, col %d) = %d" % (row,col,n))
new = answer_solve_sudoku(grid, counter+1)
if new is not False:
print_counter(counter, "answer_solve_sudoku() solved: returning")
return new
# backtrack
print_counter(counter, "backtrack")
return False
print_counter(counter, "**SOLVED! Returning back up to top**")
return grid
from pprint import pprint
solution = answer_solve_sudoku(easy_grid)
pprint(solution)
我所做的是创建一个小打印机功能,它将打印一个数字并用许多空格缩进消息。然后在你的answer_solve_sudoku
中,我给它一个默认的计数器值0,并且总是将计数器+ 1传递给每个递归调用。这样随着深度的增加,数量也会增加。我将打印机功能放在一边,以便直观地说明正在发生的事情。
你会看到的是这样的:
[0] test: (row 0, col 2) = 1
[0] test: (row 0, col 2) = 2
[0] test: (row 0, col 2) = 3
[0] test: (row 0, col 2) = 4
[1] test: (row 0, col 3) = 1
[2] test: (row 0, col 4) = 1
[2] test: (row 0, col 4) = 2
[2] test: (row 0, col 4) = 3
...
[45] test: (row 7, col 7) = 8
[45] test: (row 7, col 7) = 9
[45] backtrack
[44] test: (row 7, col 5) = 6
[44] test: (row 7, col 5) = 7
...
[51] test: (row 8, col 6) = 6
[51] test: (row 8, col 6) = 7
[52] **SOLVED! Returning back up to top**
[51] answer_solve_sudoku() solved: returning
[50] answer_solve_sudoku() solved: returning
[49] answer_solve_sudoku() solved: returning
...
[2] answer_solve_sudoku() solved: returning
[1] answer_solve_sudoku() solved: returning
[0] answer_solve_sudoku() solved: returning
返回new只会在解算器找到解决方案时调用, 这将在返回网格后立即调用
是的,当对answer_solve_sudoku
的调用通过整个循环而没有失败并到达底部时,它已成功并返回网格。然后调用者将该结果作为new = answer_solve_sudoku(grid)
的结果获得并返回。网格将在堆栈上的每个返回调用中恢复。
何时会发生回溯?
因为您要在每次递归中创建网格的副本,除非该步骤找到解决方案,否则它将对该网格所做的更改将被丢弃,因为一旦我们返回一步,我们将返回到之前的网格州。它试图尽可能地使用该解决方案,直到它超过9的值。
答案 1 :(得分:1)
您应该查看此answer。它具有伪代码和递归回溯的实际代码。代码是用Java编写的,但它与Python的思维过程相同。