繁体   English   中英

如何提高数独求解器的性能?

[英]How can I improve performance of Sudoku solver?

我无法提高以下 Sudoku Solver 代码的性能。 我知道这里有 3 个循环,它们可能会导致性能下降,但我找不到更好/更有效的方法。 “board”随着递归的每次迭代而发生变化——如果没有零剩下,我只需要退出递归。

我试图将“板”与突变隔离开来,但它并没有改变性能。 我还尝试对前 2 个“for”循环使用列表理解(即仅循环使用零的行和列),尝试查找所有零的坐标,然后通过它们使用单​​个循环到 go - 没有帮助.

我认为我在这里用递归做一些根本错误的事情 - 关于如何使解决方案更快的任何建议或建议?

def box(board,row,column):
    start_col = column - (column % 3)
    finish_col = start_col + 3
    start_row = row - (row % 3)
    finish_row = start_row + 3
    return [y for x in board[start_row:finish_row] for y in x[start_col:finish_col]]

def possible_values(board,row,column):
    values = {1,2,3,4,5,6,7,8,9}
    col_values = [v[column] for v in board]
    row_values = board[row]
    box_values = box(board, row, column)
    return (values - set(row_values + col_values + box_values))

def solve(board, i_row = 0, i_col = 0):
    for rn in range(i_row,len(board)):
        if rn != i_row: i_col = 0
        for cn in range(i_col,len(board)):
            if board[rn][cn] == 0:
                options = possible_values(board, rn, cn)
                for board[rn][cn] in options:
                    if solve(board, rn, cn): 
                        return board
                    board[rn][cn] = 0
                #if no options left for the cell, go to previous cell and try next option
                return False
    #if no zeros left on the board, problem is solved
    return True

problem = [
            [9, 0, 0, 0, 8, 0, 0, 0, 1],
            [0, 0, 0, 4, 0, 6, 0, 0, 0],
            [0, 0, 5, 0, 7, 0, 3, 0, 0],
            [0, 6, 0, 0, 0, 0, 0, 4, 0],
            [4, 0, 1, 0, 6, 0, 5, 0, 8],
            [0, 9, 0, 0, 0, 0, 0, 2, 0],
            [0, 0, 7, 0, 3, 0, 2, 0, 0],
            [0, 0, 0, 7, 0, 5, 0, 0, 0],
            [1, 0, 0, 0, 4, 0, 0, 0, 7]
        ]

solve(problem)

您可以做三件事来加快速度:

  • 使用整数的 arrays 维护额外的 state 以跟踪行、列和框候选者(或已使用的等效值),以便找到可能的值只是possible_values = row_candidates[row] & col_candidates[col] & box_candidates[box] 这是一个不变的因素,在您的方法中变化很小。
  • 正如 kosciej16 建议的那样,使用 min-remaining-values 启发式方法来选择接下来要填充的单元格。 这会将您的算法变成加密DPLL ,为您提供早期冲突检测(具有 0 个候选的单元)、约束传播(具有 1 个候选的单元)以及 rest 的较低有效分支因子。
  • 添加逻辑来检测隐藏的单曲(就像 Norvig 求解器一样)。 对于最简单的谜题,这将使您的求解器速度稍慢一些,但对于隐藏单字很重要的谜题(如 17 条线索谜题),它会产生巨大的差异。

由于 53x15 和 kosciej16,结果最终奏效。 不理想或最佳但通过了所需的性能测试:

def solve(board, i_row = 0, i_col = 0):
    cells_to_solve = [((rn, cn), possible_values(board,rn,cn)) for rn in range(len(board)) for cn in range(len(board)) if board[rn][cn] == 0]
    if not cells_to_solve: return True

    min_n_of_values = min([len(x[1]) for x in cells_to_solve])
    if min_n_of_values == 0: return False

    best_cells_to_try = [((rn,cn),options) for ((rn,cn),options) in cells_to_solve if len(options) == min_n_of_values]

    for ((rn,cn),options) in best_cells_to_try:
        for board[rn][cn] in options:
            if solve(board, rn, cn): 
                return board
            board[rn][cn] = 0
        return False

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM