python中数独的递归解

时间:2012-07-17 05:05:11

标签: python recursion sudoku

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

称为?

2 个答案:

答案 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的思维过程相同。