python中数独的递归求解

python中数独的递归求解,python,recursion,sudoku,Python,Recursion,Sudoku,这是代码,check\u sudoku(grid)可以返回网格是否为有效的数独 我只是不理解递归部分,我试着在纸上写下这个过程,但每次都失败了,回溯是如何工作的?什么是新的?如果答案\u求解\u数独(网格)有效 我知道它每隔0到1..9设置一次,并检查它是否是有效的网格,但我无法在纸上画出整个过程。我真的无法理解回溯是如何工作的 顺便问一下,对于理解递归代码有什么建议吗 致以最良好的祝愿 盛云 编辑 我一次又一次地阅读代码,现在我有了一些理解,但我不太确定这一点,如果有人给我一些意见,我会很感激

这是代码,
check\u sudoku(grid)
可以返回网格是否为有效的数独

我只是不理解递归部分,我试着在纸上写下这个过程,但每次都失败了,回溯是如何工作的?什么是新的?如果
答案\u求解\u数独(网格)
有效

我知道它每隔0到1..9设置一次,并检查它是否是有效的网格,但我无法在纸上画出整个过程。我真的无法理解回溯是如何工作的

顺便问一下,对于理解递归代码有什么建议吗

致以最良好的祝愿

盛云

编辑

我一次又一次地阅读代码,现在我有了一些理解,但我不太确定这一点,如果有人给我一些意见,我会很感激的

1、
return new
仅在解算器找到解决方案时调用,并在
return grid

2、你什么时候来

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\u sudoku(\u\u grid)
将返回
False
,如果下一个解决方案正确,它将调用另一个
answer\u solve\u sudoku(grid)
,直到它得到正确的解决方案,当它得到正确的解决方案时,它将
返回grid
,然后
返回新的
。那么什么时候是:

# backtrack
return False

打电话给?

我有一个更好的建议,而不是写在纸上。格式化代码以显示逻辑正在执行的操作的可视化表示。以下是一种方法:

def打印计数器(val,msg): 打印“%s[%d]%s%”(“”*val,val,msg) def answer_solve_数独(__网格,计数器=0): res=检查数独(网格) 如果res为无或res为假: 返回res grid=copy.deepcopy(网格) 对于xrange(9)中的行: 对于X范围(9)中的列: 如果网格[行][列]==0: 对于X范围内的n(1,10): 网格[行][列]=n 打印计数器(计数器,测试:(行%d,列%d)=%d“%(行,列,n)) 新建=回答、解决、数独(网格、计数器+1) 如果new不是False: 打印计数器(计数器,“解答数独()解答:返回”) 还新 #回溯 打印计数器(计数器,“回溯”) 返回错误 打印计数器(计数器,**已解决!返回顶部**) 回流栅 从pprint导入pprint 解决方案=答案解决数独(简易网格) pprint(解决方案) 我所做的是创建一个小的打印机函数,它将打印一个数字,并将消息缩进那么多空格。然后,在您的
答案\u求解\u数独
中,我给了它一个默认的计数器值0,并始终将计数器+1传递给每个递归调用。这样,随着深度的增加,数量也会增加。我把打印机的功能放在一起,以直观地说明正在发生的事情

您将看到如下内容:

# backtrack
return False
仅当解算器找到解决方案时,才会调用return new, 这将在返回网格后立即调用

是的,当对
answer\u solve\u sudoku
的调用通过整个循环而没有失败并到达底部时,它已经成功并返回网格。然后调用方将得到该网格作为
new=answer\u solve\u sudoku(网格)
的结果,并返回该结果。网格将备份堆栈上的每个返回调用

回溯何时发生


因为您在每个递归中创建网格的副本,除非该步骤找到解决方案,否则它对该网格所做的更改将被丢弃,因为一旦我们返回一个步骤,我们将返回到以前的网格状态。它尝试使用该解决方案尽可能多地运行,直到超过值9

你应该看看这个。它有用于递归回溯的伪代码和实际代码。代码是用Java编写的,但它与Python的思维过程相同。

更容易看到回溯如何处理较小的问题。。像4个皇后。。。看看奇怪的巧合。。。两天前刚刚回答:,相同的主题,相同的函数名。@jdi可能是因为:啊。是的,也许你们都在同一个班:-)你们可能已经在做这个了,但是当在纸上写东西的时候,逐行浏览程序是很有帮助的,以确保你们写的是程序在做什么,而不是你们认为它在做什么。我喜欢在白板上这样做,这样我就可以写出一个变量列表,并像程序一样更新它们的值。
[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