【问题标题】:recursion solution of sudoku in pythonpython中数独的递归解法
【发布时间】:2013-11-18 02:17:34
【问题描述】:
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) 可以返回一个网格是否是一个有效的数独。

我就是看不懂递归部分,我试着在纸上写下过程,但每次都失败,回溯是如何工作的?什么是newanswer_solve_sudoku(grid) 是否有效?

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

顺便说一句,对理解递归代码有什么建议吗?

最好的问候,

盛运

编辑

我一遍又一遍地阅读代码,现在我有点理解了,但是我对此不太确定,如果有人能给我一些cmets,那就太好了。

1、return new只会在求解器找到解时调用,并且会在return grid之后调用

2,什么时候会

# backtrack
return False

被调用?如果下一个解决方案不正确,check_sudoku(__grid) 将返回False,如果下一个解决方案正确,它将调用另一个answer_solve_sudoku(grid),直到它得到正确的解决方案,当它得到正确的解决方案时,它会return grid,然后是 return new。那么是什么时候:

# backtrack
return False

打电话了?

【问题讨论】:

标签: python recursion sudoku


【解决方案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,并且总是将 counter+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

return new 只会在求解器找到解决方案时调用, 这将在返回网格后立即调用

是的,当对answer_solve_sudoku 的调用通过整个循环而没有失败并到达底部时,它已经成功并返回网格。然后,调用者会将该网格作为结果发送给new = answer_solve_sudoku(grid) 并将其返回。网格将备份堆栈上的每个返回调用。

什么时候回溯?

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-17
      • 1970-01-01
      • 1970-01-01
      • 2017-12-16
      相关资源
      最近更新 更多