簡體   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