当前位置: 首页 > 知识库问答 >
问题:

数独的递归回溯

晏树
2023-03-14

我对编码还是很陌生的,我正在尝试一些稍微困难的主题,例如修改数独递归回溯程序的解决方案。最初的解决方案是针对大小为3x3的数独,我希望我的解决方案可以与正常大小的数独(9x9)一起使用。3x3解决方案在这里找到。

我觉得我对算法非常了解:对于网格中的每个列表(包含该单元格的可能值),在每一步尝试每个数字,确保电路板仍然有效,移动到下一个列表,分配一个可能的数字直到其有效,等等。如果当前电路板不正确,则回溯到最后一个仍然有效的电路板。

编辑:添加了一些函数来缩小每个空单元格的可能值,以及填充只有一个可能值的单元格。我已经验证了这些函数是否正常工作。fill_zeros仅在初始化数独时调用。make_nodes从板构造最新节点。node_to_board以节点格式接收板并以行格式返回板。refine_by函数是不言自明的。

def make_nodes(board):
    nodes = [[board[0][0], board[0][1], board[0][2],
             board[1][0], board[1][1], board[1][2],
             board[2][0], board[2][1], board[2][2]],
             [board[0][3], board[0][4], board[0][5],
              board[1][3], board[1][4], board[1][5],
              board[2][3], board[2][4], board[2][5]],
             [board[0][6], board[0][7], board[0][8],
              board[1][6], board[1][7], board[1][8],
              board[2][6], board[2][7], board[2][8]],
             [board[3][0], board[3][1], board[3][2],
              board[4][0], board[4][1], board[4][2],
              board[5][0], board[5][1], board[5][2]],
             [board[3][3], board[3][4], board[3][5],
              board[4][3], board[4][4], board[4][5],
              board[5][3], board[5][4], board[5][5]],
             [board[3][6], board[3][7], board[3][8],
              board[4][6], board[4][7], board[4][8],
              board[5][6], board[5][7], board[5][8]],
             [board[6][0], board[6][1], board[6][2],
              board[7][0], board[7][1], board[7][2],
              board[8][0], board[8][1], board[8][2]],
             [board[6][3], board[6][4], board[6][5],
              board[7][3], board[7][4], board[7][5],
              board[8][3], board[8][4], board[8][5]],
             [board[6][6], board[6][7], board[6][8],
              board[7][6], board[7][7], board[7][8],
              board[8][6], board[8][7], board[8][8]]
             ]
    return nodes


def fill_zeros(board):
    nodes = make_nodes(board)
    allnums = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    for i in range(9):
        for j in range(9):
            possible = [h for h in allnums if h not in nodes[i]]
            if nodes[i][j] == 0:
                nodes[i][j] = possible
    return nodes


def node_to_board(nodes):
    board = []
    for y in range(3):
        for i in range(0,9, 3):
            for node in nodes[(y*3):((y+1)*3)]:
                for x in range(3):
                    board.append(node[i+x])
    board = [board[pos:pos + 9] for pos in range(0, 9 * 9, 9)]
    return board


def refine_empty_by_col(board):
    for col in range(9):
        col_done = []
        for row in range(9):
            if type(board[row][col]) == int:
                col_done.append(board[row][col])
        for row in range(9):
            if type(board[row][col]) == list:
                board[row][col] = [x for x in board[row][col] if x not in col_done]
        for row in range(9):
            if type(board[row][col]) == list:
                if len(board[row][col]) == 1:
                    k = board[row][col].pop()
                    board[row][col] = k
    return board


def refine_empty_by_row(board):
    for row in range(9):
        row_done = []
        for col in range(9):
            if type(board[row][col]) == int:
                row_done.append(board[row][col])
        for col in range(9):
             if type(board[row][col]) == list:
                board[row][col] = [x for x in board[row][col] if x not in row_done]
        for col in range(9):
            if type(board[row][col]) == list:
                if len(board[row][col]) == 1:
                    k = board[row][col].pop()
                    board[row][col] = k
    return board

def refine_empty_by_node(board):
    nodes = make_nodes(board)
    allnums = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    for node in range(9):
        taken = [x for x in allnums if x in nodes[node]]
        for item in range(9):
            if type(nodes[node][item]) == list:
                nodes[node][item] = [x for x in nodes[node][item] if x not in taken]
                if len(nodes[node][item]) == 1:
                    k = nodes[node][item].pop()
                    taken.append(k)
                    nodes[node][item] = k
        node_list_nums = []
        for item in range(9):
            if type(nodes[node][item]) == list:
                node_list_nums += nodes[node][item]
        node_list_nums = [x for x in node_list_nums if node_list_nums.count(x) == 1]
        for item in range(9):
            if type(nodes[node][item]) == list:
                if any(nodes[node][item]) in node_list_nums:
                    for x in node_list_nums:
                        if x in nodes[node][item]:
                            nodes[node][item] = x
                            node_list_nums.remove(x)

    board = node_to_board(nodes)
    return board

def refine_easy_style(board):
    board_after = board
    board_orig = []
    while board_orig != board_after:
        board_orig = board_after
        board_after = refine_empty_by_col(board_orig)
        board_after = refine_empty_by_row(board_after)
        board_after = refine_empty_by_node(board_after)

    return board_after

以下是(编辑过的)辅助功能:

def is_distinct(passed):
    used = []
    for item in passed:
        if type(item) == list:
            continue
        if item in used:
            return False
        used.append(item)
    return True

def is_valid(board):
    for i in range(9):
        row = [board[i][row] for row in range(9)]
        if not is_distinct(row):
            return False

        col = [board[row][i] for row in range(9)]
        if not is_distinct(col):
            return False

    for node in make_nodes(board):
        if not is_distinct(node):
            return False

    return True

is_distinct获得一个列表,它循环通过该列表以确保每个项目都是唯一的(return True),否则返回False

是否有效包含电路板的细分部分:行、列和节点(每个3x3正方形)。然后,它将每一块电路板传递给is_distinct

(编辑过的)递归函数是

def solve_puzzle(board):
    empties = 0
    for row in board:
        for item in row:
            if type(item) == list:
                empties += 1

    if empties == 0:
        if is_valid(board):
            return board
        else:
            print('0 empties')
            return False

    for i in range(9):
        for j in range(9):
            if type(board[i][j]) == list:
                board2 = board
                for k in board2[i][j]:
                    print('trying = {}, cell-list ={}, coords = {},{}'.format(k, board2[i][j], i, j))
                    board2[i][j] = k
                    if is_valid(board2) and solve_puzzle(board2):
                        return True
                    else:
                        print('{} at slot {}, {} didnt work.'.format(k, i , j))
                    print('Backtracking here...')
                    board2[i][j] = board[i][j]
    return False

设置是:

#below this line works
inp = [int(x) for x in input().split()]
empties = inp.count(0)
board = [inp[pos:pos+9] for pos in range(0, 9*9, 9)]
board = node_to_board(fill_zeros(board))
print(board)
board = refine_easy_style(board)
print(board)
#above this line works
# below this line is testing
board = solve_puzzle(board)
print(board)

编辑:听了Prune的建议,我打了几个打印电话来输出一些有用的信息。在跟踪输出后,我认为问题在于程序在运行完所有可能的输出后如何回溯。例如:在输出中,电路板在达到(3,8)之前是有效的,然后在输出中运行,而不是回溯到之前的单元,而是移动到下一个空单元(4,1)。此外,回溯可能会走得太远;虽然第一次尝试的结果是正确的,但它表示第一次尝试的结果是正确的。

我曾尝试过其他类似风格的数独解决方案,但似乎不知道我错在哪里。

编辑:样本输入:3 0 6 5 0 8 4 0 0 5 2 0 0 0 0 0 0 8 0 0 0 0 0 0 0 3 0 0 0 8 0 0 8 6 0 5 0 0 0 0 9 0 0 0 6 0 1 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0

样本:

[[3, [1, 4, 9], 6, 5, [1, 2, 3, 4, 6, 7, 9], 8, 4, [2, 5, 6, 7, 8, 9], [2, 5, 6, 7, 8, 9]], [5, 2, [1, 4, 9], [1, 2, 3, 4, 6, 7, 9], [1, 2, 3, 4, 6, 7, 9], [1, 2, 3, 4, 6, 7, 9], [2, 5, 6, 7, 8, 9], [2, 5, 6, 7, 8, 9], [2, 5, 6, 7, 8, 9]], [[1, 4, 9], 8, 7, [1, 2, 3, 4, 6, 7, 9], [1, 2, 3, 4, 6, 7, 9], [1, 2, 3, 4, 6, 7, 9], [2, 5, 6, 7, 8, 9], 3, 1], [[1, 2, 4, 6, 7, 8], [1, 2, 4, 6, 7, 8], 3, [2, 4, 5, 7], 1, [2, 4, 5, 7], [1, 2, 3, 4, 7, 9], 8, [1, 2, 3, 4, 7, 9]], [9, [1, 2, 4, 6, 7, 8], [1, 2, 4, 6, 7, 8], 8, 6, 3, [1, 2, 3, 4, 7, 9], [1, 2, 3, 4, 7, 9], 5], [[1, 2, 4, 6, 7, 8], 5, [1, 2, 4, 6, 7, 8], [2, 4, 5, 7], 9, [2, 4, 5, 7], 6, [1, 2, 3, 4, 7, 9], [1, 2, 3, 4, 7, 9]], [1, 3, [2, 4, 6, 7, 8, 9], [1, 3, 4, 5, 7, 8, 9], [1, 3, 4, 5, 7, 8, 9], [1, 3, 4, 5, 7, 8, 9], 2, 5, [1, 6, 8, 9]], [[2, 4, 6, 7, 8, 9], [2, 4, 6, 7, 8, 9], [2, 4, 6, 7, 8, 9], [1, 3, 4, 5, 7, 8, 9], [1, 3, 4, 5, 7, 8, 9], [1, 3, 4, 5, 7, 8, 9], [1, 6, 8, 9], 7, 4], [[2, 4, 6, 7, 8, 9], [2, 4, 6, 7, 8, 9], 5, 2, [1, 3, 4, 5, 7, 8, 9], 6, 3, [1, 6, 8, 9], [1, 6, 8, 9]]]
[[3, [1, 9], 6, 5, 7, 8, 4, [2, 9], [2, 9]], [5, 2, [1, 9], [1, 3, 4], [3, 4], [1, 4], [7, 8, 9], [6, 9], [6, 7, 8, 9]], [4, 8, 7, 6, 2, 9, 5, 3, 1], [[2, 6, 7], [4, 6, 7], 3, [4, 7], 1, [2, 4, 5, 7], [7, 9], 8, [2, 7, 9]], [9, [1, 4, 7], [1, 2, 4], 8, 6, 3, [1, 7], [1, 2, 4], 5], [[2, 7, 8], 5, [1, 2, 4, 8], [4, 7], 9, [2, 4, 7], 6, [1, 2, 4], [2, 3, 7]], [1, 3, [4, 8, 9], [4, 7, 9], [4, 8], [4, 7], 2, 5, [6, 8, 9]], [[2, 6, 8], [6, 9], [2, 8, 9], [1, 3, 9], [3, 5, 8], [1, 5], [1, 8, 9], 7, 4], [[7, 8], [4, 7, 9], 5, 2, [4, 8], 6, 3, [1, 9], [8, 9]]]
trying = 1, board-list =[1, 9], coords = 0,1
trying = 2, board-list =[2, 9], coords = 0,7
trying = 2, board-list =[2, 9], coords = 0,8
2 at slot 0, 8 didnt work.
Backtracking here...
trying = 9, board-list =2, coords = 0,8
trying = 1, board-list =[1, 9], coords = 1,2
1 at slot 1, 2 didnt work.
Backtracking here...
trying = 9, board-list =1, coords = 1,2
trying = 1, board-list =[1, 3, 4], coords = 1,3
trying = 3, board-list =[3, 4], coords = 1,4
trying = 1, board-list =[1, 4], coords = 1,5
1 at slot 1, 5 didnt work.
Backtracking here...
trying = 4, board-list =1, coords = 1,5
trying = 7, board-list =[7, 8, 9], coords = 1,6
trying = 6, board-list =[6, 9], coords = 1,7
trying = 6, board-list =[6, 7, 8, 9], coords = 1,8
6 at slot 1, 8 didnt work.
Backtracking here...
trying = 7, board-list =6, coords = 1,8
7 at slot 1, 8 didnt work.
Backtracking here...
trying = 8, board-list =7, coords = 1,8
trying = 2, board-list =[2, 6, 7], coords = 3,0
trying = 4, board-list =[4, 6, 7], coords = 3,1
trying = 4, board-list =[4, 7], coords = 3,3
4 at slot 3, 3 didnt work.
Backtracking here...
trying = 7, board-list =4, coords = 3,3
trying = 2, board-list =[2, 4, 5, 7], coords = 3,5
2 at slot 3, 5 didnt work.
Backtracking here...
trying = 4, board-list =2, coords = 3,5
4 at slot 3, 5 didnt work.
Backtracking here...
trying = 5, board-list =4, coords = 3,5
trying = 7, board-list =[7, 9], coords = 3,6
7 at slot 3, 6 didnt work.
Backtracking here...
trying = 9, board-list =7, coords = 3,6
trying = 2, board-list =[2, 7, 9], coords = 3,8
2 at slot 3, 8 didnt work.
Backtracking here...
trying = 7, board-list =2, coords = 3,8
7 at slot 3, 8 didnt work.
Backtracking here...
trying = 9, board-list =7, coords = 3,8
9 at slot 3, 8 didnt work.
Backtracking here...
trying = 1, board-list =[1, 4, 7], coords = 4,1
1 at slot 4, 1 didnt work.
Backtracking here...
trying = 4, board-list =1, coords = 4,1
4 at slot 4, 1 didnt work.
Backtracking here...
trying = 7, board-list =4, coords = 4,1
7 at slot 4, 1 didnt work.
Backtracking here...
trying = 1, board-list =[1, 2, 4], coords = 4,2
1 at slot 4, 2 didnt work.
Backtracking here...
trying = 2, board-list =1, coords = 4,2
2 at slot 4, 2 didnt work.
Backtracking here...
trying = 4, board-list =2, coords = 4,2
4 at slot 4, 2 didnt work.
Backtracking here...
trying = 1, board-list =[1, 7], coords = 4,6
1 at slot 4, 6 didnt work.
Backtracking here...
trying = 7, board-list =1, coords = 4,6
7 at slot 4, 6 didnt work.
Backtracking here...
trying = 1, board-list =[1, 2, 4], coords = 4,7
1 at slot 4, 7 didnt work.
Backtracking here...
trying = 2, board-list =1, coords = 4,7
2 at slot 4, 7 didnt work.
Backtracking here...
trying = 4, board-list =2, coords = 4,7
4 at slot 4, 7 didnt work.
Backtracking here...
trying = 2, board-list =[2, 7, 8], coords = 5,0
2 at slot 5, 0 didnt work.
Backtracking here...
trying = 7, board-list =2, coords = 5,0
7 at slot 5, 0 didnt work.
Backtracking here...
trying = 8, board-list =7, coords = 5,0
8 at slot 5, 0 didnt work.
Backtracking here...
trying = 1, board-list =[1, 2, 4, 8], coords = 5,2
1 at slot 5, 2 didnt work.
Backtracking here...
trying = 2, board-list =1, coords = 5,2
2 at slot 5, 2 didnt work.
Backtracking here...
trying = 4, board-list =2, coords = 5,2
4 at slot 5, 2 didnt work.
Backtracking here...
trying = 8, board-list =4, coords = 5,2
8 at slot 5, 2 didnt work.
Backtracking here...
trying = 4, board-list =[4, 7], coords = 5,3
4 at slot 5, 3 didnt work.
Backtracking here...
trying = 7, board-list =4, coords = 5,3
7 at slot 5, 3 didnt work.
Backtracking here...
trying = 2, board-list =[2, 4, 7], coords = 5,5
2 at slot 5, 5 didnt work.
Backtracking here...
trying = 4, board-list =2, coords = 5,5
4 at slot 5, 5 didnt work.
Backtracking here...
trying = 7, board-list =4, coords = 5,5
7 at slot 5, 5 didnt work.
Backtracking here...
trying = 1, board-list =[1, 2, 4], coords = 5,7
1 at slot 5, 7 didnt work.
Backtracking here...
trying = 2, board-list =1, coords = 5,7
2 at slot 5, 7 didnt work.
Backtracking here...
trying = 4, board-list =2, coords = 5,7
4 at slot 5, 7 didnt work.
Backtracking here...
trying = 2, board-list =[2, 3, 7], coords = 5,8
2 at slot 5, 8 didnt work.
Backtracking here...
trying = 3, board-list =2, coords = 5,8
3 at slot 5, 8 didnt work.
Backtracking here...
trying = 7, board-list =3, coords = 5,8
7 at slot 5, 8 didnt work.
Backtracking here...
trying = 4, board-list =[4, 8, 9], coords = 6,2
4 at slot 6, 2 didnt work.
Backtracking here...
trying = 8, board-list =4, coords = 6,2
8 at slot 6, 2 didnt work.
Backtracking here...
trying = 9, board-list =8, coords = 6,2
9 at slot 6, 2 didnt work.
Backtracking here...
trying = 4, board-list =[4, 7, 9], coords = 6,3
4 at slot 6, 3 didnt work.
Backtracking here...
trying = 7, board-list =4, coords = 6,3
7 at slot 6, 3 didnt work.
Backtracking here...
trying = 9, board-list =7, coords = 6,3
9 at slot 6, 3 didnt work.
Backtracking here...
trying = 4, board-list =[4, 8], coords = 6,4
4 at slot 6, 4 didnt work.
Backtracking here...
trying = 8, board-list =4, coords = 6,4
8 at slot 6, 4 didnt work.
Backtracking here...
trying = 4, board-list =[4, 7], coords = 6,5
4 at slot 6, 5 didnt work.
Backtracking here...
trying = 7, board-list =4, coords = 6,5
7 at slot 6, 5 didnt work.
Backtracking here...
trying = 6, board-list =[6, 8, 9], coords = 6,8
6 at slot 6, 8 didnt work.
Backtracking here...
trying = 8, board-list =6, coords = 6,8
8 at slot 6, 8 didnt work.
Backtracking here...
trying = 9, board-list =8, coords = 6,8
9 at slot 6, 8 didnt work.
Backtracking here...
trying = 2, board-list =[2, 6, 8], coords = 7,0
2 at slot 7, 0 didnt work.
Backtracking here...
trying = 6, board-list =2, coords = 7,0
6 at slot 7, 0 didnt work.
Backtracking here...
trying = 8, board-list =6, coords = 7,0
8 at slot 7, 0 didnt work.
Backtracking here...
trying = 6, board-list =[6, 9], coords = 7,1
6 at slot 7, 1 didnt work.
Backtracking here...
trying = 9, board-list =6, coords = 7,1
9 at slot 7, 1 didnt work.
Backtracking here...
trying = 2, board-list =[2, 8, 9], coords = 7,2
2 at slot 7, 2 didnt work.
Backtracking here...
trying = 8, board-list =2, coords = 7,2
8 at slot 7, 2 didnt work.
Backtracking here...
trying = 9, board-list =8, coords = 7,2
9 at slot 7, 2 didnt work.
Backtracking here...
trying = 1, board-list =[1, 3, 9], coords = 7,3
1 at slot 7, 3 didnt work.
Backtracking here...
trying = 3, board-list =1, coords = 7,3
3 at slot 7, 3 didnt work.
Backtracking here...
trying = 9, board-list =3, coords = 7,3
9 at slot 7, 3 didnt work.
Backtracking here...
trying = 3, board-list =[3, 5, 8], coords = 7,4
3 at slot 7, 4 didnt work.
Backtracking here...
trying = 5, board-list =3, coords = 7,4
5 at slot 7, 4 didnt work.
Backtracking here...
trying = 8, board-list =5, coords = 7,4
8 at slot 7, 4 didnt work.
Backtracking here...
trying = 1, board-list =[1, 5], coords = 7,5
1 at slot 7, 5 didnt work.
Backtracking here...
trying = 5, board-list =1, coords = 7,5
5 at slot 7, 5 didnt work.
Backtracking here...
trying = 1, board-list =[1, 8, 9], coords = 7,6
1 at slot 7, 6 didnt work.
Backtracking here...
trying = 8, board-list =1, coords = 7,6
8 at slot 7, 6 didnt work.
Backtracking here...
trying = 9, board-list =8, coords = 7,6
9 at slot 7, 6 didnt work.
Backtracking here...
trying = 7, board-list =[7, 8], coords = 8,0
7 at slot 8, 0 didnt work.
Backtracking here...
trying = 8, board-list =7, coords = 8,0
8 at slot 8, 0 didnt work.
Backtracking here...
trying = 4, board-list =[4, 7, 9], coords = 8,1
4 at slot 8, 1 didnt work.
Backtracking here...
trying = 7, board-list =4, coords = 8,1
7 at slot 8, 1 didnt work.
Backtracking here...
trying = 9, board-list =7, coords = 8,1
9 at slot 8, 1 didnt work.
Backtracking here...
trying = 4, board-list =[4, 8], coords = 8,4
4 at slot 8, 4 didnt work.
Backtracking here...
trying = 8, board-list =4, coords = 8,4
8 at slot 8, 4 didnt work.
Backtracking here...
trying = 1, board-list =[1, 9], coords = 8,7
1 at slot 8, 7 didnt work.
Backtracking here...
trying = 9, board-list =1, coords = 8,7
9 at slot 8, 7 didnt work.
Backtracking here...
trying = 8, board-list =[8, 9], coords = 8,8
8 at slot 8, 8 didnt work.
Backtracking here...
trying = 9, board-list =8, coords = 8,8
9 at slot 8, 8 didnt work.
Backtracking here...
9 at slot 3, 6 didnt work.
Backtracking here...
5 at slot 3, 5 didnt work.
Backtracking here...
trying = 7, board-list =5, coords = 3,5
7 at slot 3, 5 didnt work.
Backtracking here...
7 at slot 3, 3 didnt work.
Backtracking here...
4 at slot 3, 1 didnt work.
Backtracking here...
trying = 6, board-list =4, coords = 3,1
6 at slot 3, 1 didnt work.
Backtracking here...
trying = 7, board-list =6, coords = 3,1
7 at slot 3, 1 didnt work.
Backtracking here...
2 at slot 3, 0 didnt work.
Backtracking here...
trying = 6, board-list =2, coords = 3,0
6 at slot 3, 0 didnt work.
Backtracking here...
trying = 7, board-list =6, coords = 3,0
7 at slot 3, 0 didnt work.
Backtracking here...
8 at slot 1, 8 didnt work.
Backtracking here...
trying = 9, board-list =8, coords = 1,8
9 at slot 1, 8 didnt work.
Backtracking here...
6 at slot 1, 7 didnt work.
Backtracking here...
trying = 9, board-list =6, coords = 1,7
9 at slot 1, 7 didnt work.
Backtracking here...
7 at slot 1, 6 didnt work.
Backtracking here...
trying = 8, board-list =7, coords = 1,6
8 at slot 1, 6 didnt work.
Backtracking here...
trying = 9, board-list =8, coords = 1,6
9 at slot 1, 6 didnt work.
Backtracking here...
4 at slot 1, 5 didnt work.
Backtracking here...
3 at slot 1, 4 didnt work.
Backtracking here...
trying = 4, board-list =3, coords = 1,4
4 at slot 1, 4 didnt work.
Backtracking here...
1 at slot 1, 3 didnt work.
Backtracking here...
trying = 3, board-list =1, coords = 1,3
3 at slot 1, 3 didnt work.
Backtracking here...
trying = 4, board-list =3, coords = 1,3
4 at slot 1, 3 didnt work.
Backtracking here...
9 at slot 1, 2 didnt work.
Backtracking here...
9 at slot 0, 8 didnt work.
Backtracking here...
2 at slot 0, 7 didnt work.
Backtracking here...
trying = 9, board-list =2, coords = 0,7
9 at slot 0, 7 didnt work.
Backtracking here...
1 at slot 0, 1 didnt work.
Backtracking here...
trying = 9, board-list =1, coords = 0,1
9 at slot 0, 1 didnt work.
Backtracking here...
False

更正:3 1 6 5 7 8 4 9 2 5 2 9 1 3 4 7 6 6 2 9 5 3 1 2 6 4 1 5 9 8 7 4 6 3 1 2 5 8 1 7 9 2 6 3 3 1 8 7 2 6 6 9 2 2 3 3 5 1 7 4 7 4 4 4 5 8 3 1 9

数独格式的正确答案:

3 1 6 5 7 8 4 9 2

5 2 9 1 3 4 7 6 8

4 8 7 6 2 9 5 3 1

2 6 3 4 1 5 9 8 7

9 7 4 8 6 3 1 2 5

8 5 1 7 9 2 6 4 3

1 3 8 9 4 7 2 5 6

6 9 2 3 5 1 8 7 4

7 4 5 2 8 6 3 1 9

共有1个答案

魏波娃
2023-03-14

由OP解决。工作代码为:

def make_nodes(board):
    '''
    make_nodes converts a board compiled of 1x9 rows to a board compiled of 3x3 nodes
    :param board:
    :return nodes:
    '''
    nodes = [[board[0][0], board[0][1], board[0][2],
             board[1][0], board[1][1], board[1][2],
             board[2][0], board[2][1], board[2][2]],
             [board[0][3], board[0][4], board[0][5],
              board[1][3], board[1][4], board[1][5],
              board[2][3], board[2][4], board[2][5]],
             [board[0][6], board[0][7], board[0][8],
              board[1][6], board[1][7], board[1][8],
              board[2][6], board[2][7], board[2][8]],
             [board[3][0], board[3][1], board[3][2],
              board[4][0], board[4][1], board[4][2],
              board[5][0], board[5][1], board[5][2]],
             [board[3][3], board[3][4], board[3][5],
              board[4][3], board[4][4], board[4][5],
              board[5][3], board[5][4], board[5][5]],
             [board[3][6], board[3][7], board[3][8],
              board[4][6], board[4][7], board[4][8],
              board[5][6], board[5][7], board[5][8]],
             [board[6][0], board[6][1], board[6][2],
              board[7][0], board[7][1], board[7][2],
              board[8][0], board[8][1], board[8][2]],
             [board[6][3], board[6][4], board[6][5],
              board[7][3], board[7][4], board[7][5],
              board[8][3], board[8][4], board[8][5]],
             [board[6][6], board[6][7], board[6][8],
              board[7][6], board[7][7], board[7][8],
              board[8][6], board[8][7], board[8][8]]
             ]
    return nodes


def fill_zeros(board):
    '''
    fill_zeros replaces every empty 0 with the possible values for that cell based off given values in its node
    :param board:
    :return board:
    '''
    nodes = make_nodes(board)
    allnums = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    for i in range(9):
        for j in range(9):
            possible = [h for h in allnums if h not in nodes[i]]
            if nodes[i][j] == 0:
                nodes[i][j] = possible
    return nodes


def node_to_board(nodes):
    '''
    node_to_board converts a board compiled of 3x3 nodes to a board of 1x9 rows
    :param nodes:
    :return board:
    '''
    board = []
    for y in range(3):
        for i in range(0,9, 3):
            for node in nodes[(y*3):((y+1)*3)]:
                for x in range(3):
                    board.append(node[i+x])
    board = [board[pos:pos + 9] for pos in range(0, 9 * 9, 9)]
    return board


def refine_empty_by_col(board):
    '''
    refine_empty_by_col takes a board with empty cells, and checks each number in the empty cells. If the number
    is already a definitenumber in its own column, remove that number from the possible values for that cell
    :param board:
    :return board:
    '''
    for col in range(9):
        col_done = []
        for row in range(9):
            if type(board[row][col]) == int:
                col_done.append(board[row][col])
        for row in range(9):
            if type(board[row][col]) == list:
                board[row][col] = [x for x in board[row][col] if x not in col_done]
        for row in range(9):
            if type(board[row][col]) == list:
                if len(board[row][col]) == 1:
                    k = board[row][col].pop()
                    board[row][col] = k
    return board


def refine_empty_by_row(board):
    '''
    refine_empty_by_row takes a board with empty cells, and checks each number in the empty cells. If the number is
    already a definite number in its own row, remove that number from the possible values for that cell
    :param board:
    :return board:
    '''
    for row in range(9):
        row_done = []
        for col in range(9):
            if type(board[row][col]) == int:
                row_done.append(board[row][col])
        for col in range(9):
             if type(board[row][col]) == list:
                board[row][col] = [x for x in board[row][col] if x not in row_done]
        for col in range(9):
            if type(board[row][col]) == list:
                if len(board[row][col]) == 1:
                    k = board[row][col].pop()
                    board[row][col] = k
    return board


def refine_empty_by_node(board):
    '''
    refine_empty_by_node takes a board with empty cells, and checks each number in the empty cells. If the number is
    already a definite number in its own node, remove that number from the possible values for that cell
    :param board:
    :return board:
    '''
    nodes = make_nodes(board)
    allnums = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    for node in range(9):
        taken = [x for x in allnums if x in nodes[node]]
        for item in range(9):
            if type(nodes[node][item]) == list:
                nodes[node][item] = [x for x in nodes[node][item] if x not in taken]
                if len(nodes[node][item]) == 1:
                    k = nodes[node][item].pop()
                    taken.append(k)
                    nodes[node][item] = k
        node_list_nums = []
        for item in range(9):
            if type(nodes[node][item]) == list:
                node_list_nums += nodes[node][item]
        node_list_nums = [x for x in node_list_nums if node_list_nums.count(x) == 1]
        for item in range(9):
            if type(nodes[node][item]) == list:
                if any(nodes[node][item]) in node_list_nums:
                    for x in node_list_nums:
                        if x in nodes[node][item]:
                            nodes[node][item] = x
                            node_list_nums.remove(x)

    board = node_to_board(nodes)
    return board


def refine_easy_style(board):
    '''
    refine_easy_style takes a "fresh" board and repeatedly calls refine_empty_by_* until no more changes can be made
    using this method.
    :param board:
    :return board:
    '''
    board_after = board
    board_orig = []
    while board_orig != board_after:
        board_orig = board_after
        board_after = refine_empty_by_col(board_orig)
        board_after = refine_empty_by_row(board_after)
        board_after = refine_empty_by_node(board_after)

    return board_after

## above this line works
## below this line is testing


def is_distinct(passed):
    '''
    is_distinct checks to ensure the (node|row|column) is has only unique definite values (True) if not return False
    :param passed:
    :return True if all distinct definites, False otherwise:
    '''
    used = []
    for item in passed:
        if type(item) == list:
            continue
        if item in used:
            return False
        used.append(item)
    return True


def is_valid(board):
    '''
    is_valid ensures the entire board is still valid by checking each row, column and node via is_distinct
    :param board:
    :return True if valid board, False otherwise:
    '''
    for i in range(9):
        row = [board[i][row] for row in range(9)]
        if not is_distinct(row):
            return False

        col = [board[row][i] for row in range(9)]
        if not is_distinct(col):
            return False

    for node in make_nodes(board):
        if not is_distinct(node):
            return False

    return True


def next_empty(board):
    '''
    next_empty finds the next empty cell on the board, based on how many possibilities that empty cell has in
    ascending order
    :param board:
    :return x,y coords:
    '''
    min = [x for x in range(9)]
    row = 0
    col = 0
    for i in range(9):
        for j in range(9):
            if type(board[i][j]) == list:
                if len(board[i][j]) < len(min):
                    min = board[i][j]
                    row = i
                    col = j
    return row, col


def solve_puzzle(board):
    '''
    solve_puzzle recursively calls itself until the board is solved or a solution is not found
    :param board:
    :return True if solved, False if no solution exists:
    '''
    # if there are no empty cells left, ensure the board is valid
    empties = 0
    for row in board:
        for item in row:
            if type(item) == list:
                empties += 1
    if empties == 0:
        return is_valid(board)

    # get the next empty cell coords
    row, col = next_empty(board)
    board2 = board
    possible = board2[row][col]
    # recursive step
    # loop through every possible value until one is valid, backtracking until a valid board is found
    for k in possible:
        board2[row][col] = k
        if is_valid(board2) and solve_puzzle(board2):
            return True
        board2[row][col] = possible
    return False


# read input
inp = [int(x) for x in input().split()]

# make a board from the input (row-format)
board = [inp[pos:pos+9] for pos in range(0, 9*9, 9)]

# fill zeros with possible values, then put it back to row-format
board = node_to_board(fill_zeros(board))

# fill in what is possible without recursion
board = refine_easy_style(board)

# solve the remaining cells with recursion
solve_puzzle(board)
for row in board:
    print(row)

抽样调查:306050804000502007000100010008090806030060605000200505020050505050505050505050505000400050020005060300

样本:

[3, 1, 6, 5, 7, 8, 4, 9, 2]
[5, 2, 9, 1, 3, 4, 7, 6, 8]
[4, 8, 7, 6, 2, 9, 5, 3, 1]
[2, 6, 3, 4, 1, 5, 9, 8, 7]
[9, 7, 4, 8, 6, 3, 1, 2, 5]
[8, 5, 1, 7, 9, 2, 6, 4, 3]
[1, 3, 8, 9, 4, 7, 2, 5, 6]
[6, 9, 2, 3, 5, 1, 8, 7, 4]
[7, 4, 5, 2, 8, 6, 3, 1, 9]
 类似资料:
  • 我的问题是,当一个9不能正确添加时,该方法会中断。不知何故,我不知道如何让它回到前一点,并向上数,这将创建一个新的“路径”,所以我想如果我做对了,一切都应该很好。我仍然在使用递归:-/ 正如我所知,我认为Sudokurecrect()做了它应该做的事情。编辑:您可以忽略布尔测试。我知道我不使用它,我试着想一些东西,但显然我不知道如何使用它。 输出为 在那之后,不管检查哪个变体。所以问题是一样的。

  • 我正在做一个小的个人数独游戏,并试图扩展它。 到目前为止,我使用递归回溯方法使“Solve”部分正常工作,每当它设法解决递归时,就会返回true。 现在我正在尝试构建一个独特的解决方案板生成器,我在网上找到了很多关于如何实现它的信息。 然而,我在第一步很挣扎,这是我的布尔递归回溯算法变成一个递归算法,它保留了一个可能解决方案的计数。这对于检查我生成的板是否是唯一的至关重要。 更重要的是,我意识到我

  • 我正在开发高级培养皿网络编辑器/模拟器。首先,这里有一些词汇 圆圈=位置 矩形=过渡 就地整数 = 标记 过渡状态=防护 我被困在通过过渡的守卫。守卫是一个条件,如果你想执行转换,这需要是真的。我知道我应该以某种方式使用回溯,但我不知道在程序开始之前进入过渡的位置数,所以我不能使用循环,因为我不知道我需要多少个循环。 所以,我想从第一位获取第一个令牌,从第二位获取第一令牌,然后尝试通过守卫,如果通

  • 我正在用Java构建一个数独求解器,我正在使用回溯算法。有一个堆栈溢出错误,我怀疑在我的代码中有无限递归。我知道我提供的信息很少,但我太难了,不知道该怎么做。 网格是一个9乘9的数组,表示每个数独平方,它保存一个名为“value”的自定义类型,该类型简单地包含一个整数和一个布尔值,“IsOriginal”指示该值是给定的还是可更改的。 “moveon”是一个全局变量,它的值在“checkall”中

  • 我知道这个问题已经被问过很多次了,但是我的问题有点不同。这个任务要求我不验证一个字符串是否是回文——而是验证一个字符串中有多少回文(返回为“int”)。这应该使用迭代函数来完成 以下是我的迭代函数代码供参考: 我只是很难把它转换成递归函数。感谢所有帮助!

  • 问题内容: 我创建了一个Sudoku Backtracking解算器,并且效果很好,但是现在我想给出一个错误,如果该数独无法解决,因为它是无效的,例如如果给出了这个数独: http://img5.imageshack.us/img5/2241/sudokugq.jpg 如果无法解决,我该怎么办才能使我的解决方法出错?我总是以零结束或陷入循环。 问题答案: 当然,当您触及代码时,您刚刚尝试了平方中的