Python 如何为数独解算器优化包含回溯的函数运行速度

Python 如何为数独解算器优化包含回溯的函数运行速度,python,Python,最近,我正在整理和调试我的函数,这是一个回溯数独解算器,并意识到它不会在更大的数独板上完成运行: 我的代码: def areLegalValues(values: list): if len(values) in [1,4,9,16,25]: for value in values: if value <= len(values): if value != 0 and values.count(value)&g

最近,我正在整理和调试我的函数,这是一个回溯数独解算器,并意识到它不会在更大的数独板上完成运行:

我的代码:

def areLegalValues(values: list):
    if len(values) in [1,4,9,16,25]:
        for value in values:
            if value <= len(values):
                if value != 0 and values.count(value)>1:
                    return False
            else:
                return False
        return True
    return False

def isLegalRow(board: list, row: list):
    compareList = [ ]

    for r in range(len(board)):

        if r == row:

            for c in range(len(board[0])):
                #print(board[r][c])
                compareList.append(board[r][c])
    return areLegalValues(compareList)

def isLegalCol(board: list, col: list):
    compareList = [ ]
    for r in range(len(board)):
        for c in range(len(board[0])):
            if c == col:
                compareList.append(board[r][c])
                #print(compareList)
    return areLegalValues(compareList)

def isLegalBlock(board: list, block: list):
    compareList = [ ]
    N = int((len(board))**(1/2))
    blockRowNumber = int(block//N)
    blockColNumber = int(block%N)
    for row in range(blockRowNumber*N, blockRowNumber*N+N):
        #print(row)
        for col in range(len(board[0])):
            if col in range(blockColNumber*N, blockColNumber*N+N):
                #print(board[row][col])
                compareList.append(board[row][col])
                # print(compareList)
    return areLegalValues(compareList)

def isLegalSudoku(board: list):
    boardLength = len(board)
    for row in range(len(board)):
        if isLegalRow(board,row) != True:
            return False
        for col in range(len(board[0])):
            if isLegalCol(board,col) != True:
                return False
    for block in range(boardLength):
        if isLegalBlock(board, block) != True:
            return False
    return True

def solveSudoku(board: list):
    """takes in a sudoku board and solves the board through use of backtracking
    and returns the dectructively changed board"""
    checkZeroes = True
    for row in range(len(board)):
        for col in range(len(board[0])):
            if board[row][col] == 0:
                checkZeroes = False
    
    if checkZeroes == True:
        return board
    else:
        for row in range(len(board)):
            for col in range(len(board[0])):
                if board[row][col] == 0:
                    for number in range(1,len(board)+1):
                        board[row][col] = number
                        if isLegalSudoku(board) == True:
                            solution = solveSudoku(board)
                            if solution != None:
                                return solution
                        board[row][col] = 0
                    return None
def arelegalvalvalue(值:列表):
如果[1,4,9,16,25]中的len(值):
对于值中的值:
如果值为1:
返回错误
其他:
返回错误
返回真值
返回错误
def isLegalRow(板:列表,行:列表):
比较列表=[]
对于范围内的r(透镜(板)):
如果r==行:
对于范围内的c(len(板[0]):
#打印(电路板[r][c])
比较列表追加(板[r][c])
返回areLegalValues(比较列表)
def isLegalCol(板:列表,列:列表):
比较列表=[]
对于范围内的r(透镜(板)):
对于范围内的c(len(板[0]):
如果c==col:
比较列表追加(板[r][c])
#打印(比较列表)
返回areLegalValues(比较列表)
def isLegalBlock(板:列表,块:列表):
比较列表=[]
N=整数((长(板))**(1/2))
blockRowNumber=int(block//N)
blockColNumber=int(块%N)
对于范围内的行(blockRowNumber*N,blockRowNumber*N+N):
#打印(行)
对于范围内的列(len(板[0]):
如果列在范围内(blockColNumber*N,blockColNumber*N+N):
#打印(板[行][列])
compareList.append(板[行][列])
#打印(比较列表)
返回areLegalValues(比较列表)
def isLegalSudoku(电路板:列表):
boardLength=len(板)
对于范围内的行(len(board)):
如果isLegalRow(板,行)!=正确:
返回错误
对于范围内的列(len(板[0]):
如果isLegalCol(板、柱)!=正确:
返回错误
对于范围内的块(板长):
如果isLegalBlock(板、块)!=正确:
返回错误
返回真值
数独(棋盘:列表):
“”“接收数独板,并通过使用回溯来解决该板
并返回已彻底更改的板“”
检查零=真
对于范围内的行(len(board)):
对于范围内的列(len(板[0]):
如果线路板[行][列]==0:
检查零=假
如果checkZeroes==True:
返回板
其他:
对于范围内的行(len(board)):
对于范围内的列(len(板[0]):
如果线路板[行][列]==0:
对于范围(1,长度(板)+1)内的数字:
板[行][列]=编号
如果isLegalSudoku(电路板)=真:
解决方案=数独(棋盘)
如果是解决方案!=无:
返回溶液
线路板[行][列]=0
一无所获
我想知道如何优化/简化它,使其运行更快,并且可以处理更大的输入大小,而不需要花费很长时间


谢谢

正如其他人在评论中提到的,您可能需要重新考虑该算法,因为回溯非常缓慢

也就是说,从技术上讲,有一些方法可以稍微优化这一点。例如,您可以预先计算缺少的数字(您可以根据网格的大小在网格中保留每个值的某个数字),并记录每个值缺少的数量,而不是为每个零尝试每个数字。然后,一旦你用完了一个数字的分配数量,if将不再尝试将其放入网格中

例如,网格

[
[0,2,3,4],
[0,4,1,0],
[2,3,4,1],
[4,1,0,3],
[
缺少1
1
、1
3
和2
2
s。您不必尝试放置任何四个数字,对于前1或2个数字,您只有3个选项可供选择,然后再递减。对于少部分缺失值,这将是一个重大改进,对于较大的网格,这将是一个次要改进


你可以做的另一个改进是在法律委员会进行检查。与检查行、列和区域的实际值不同,您可以简单地求和并检查它们是否都等于正确的值(从1求和到电路板的大小)。例如,在尺寸为9的电路板上,所有行、列和区域的总和应为45。在4号船上,它们的总数应为10。这种方法的一个缺点是,它无法区分董事会是否有任何非法移动,或者只是缺少一个条目。因此,这只能用于检查没有剩余零的电路板。

可能没有比回溯更慢的算法来解决类似问题。我会推荐关于问题复杂性的文献。我会研究使用逻辑规则来决定哪些数字可以被确定,并使用轮流尝试每个数字作为最后手段。SudokuWiki是一个很好的网站,它提供了你想要的规则。前6名将是一个良好的开端。