微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

数独求解器具有约束满足的回溯迭代 DFS

如何解决数独求解器具有约束满足的回溯迭代 DFS

我正在尝试使用具有回溯和约束满足的迭代 DFS 算法编写数独求解器。

def sudoku_solver(sudoku):
    states = []
    ste_Hsh = set()
    visited = []
    novisited = 0
    states.append(sudoku)
    ste_Hsh.add(str(sudoku))
    visited.append(False)
    r = findRemaining(sudoku)
    while not all(visited):
        if isSolved(sudoku):
            return sudoku
        
        if not visited[novisited]:
            sudoku,r  = pickValAndProp(findNewPos(sudoku,r),sudoku.copy(),r,ste_Hsh) 
        else:
            try:
                novisited = len(visited) - visited[::-1].index(False) -1
            except:
                break
            sudoku = states[novisited]
        if isinstance(sudoku,int):
            visited[novisited] = True
            try:
                novisited = len(visited) - visited[::-1].index(False) -1
            except:
                break
            sudoku = states[novisited]
            r = findRemaining(sudoku)
            continue
        ste_Hsh.add(str(sudoku))
        if len(ste_Hsh) > len(states):
            if novisited == len(states)-1:
                states.append(sudoku)
                visited.append(False)
            else:
                states[novisited+1] = sudoku
                visited[novisited+1] = False
            novisited += 1
            
        
    return np.full((9,9),-1,dtype=int)

这是我的求解器函数

findRemaining() 返回每行 (r[2])、列 (r[1]) 和正方形 (3x3 网格) (r[0]) 的剩余可能值列表。

findNewPos() 返回要填充的下一个位置,它通过查找具有最小可能值的单元格(使用行、列和正方形的剩余值的总长度的复合度量进行评估)来完成单元格在)

pickValAndProp 是传播算法,见下文:

def pickValAndProp(new_pos,sudoku,ste_Hsh):
    try:
        val = 0
        tried = set()
        noOfStates = len(ste_Hsh)
        i = 0

        while noOfStates == len(ste_Hsh):

            val = r[1][new_pos[1]][i]
            if val in r[0][locateSquareOfPos(new_pos,sudoku)] and val in r[2][new_pos[0]]:
                sudoku[new_pos[0]][new_pos[1]] = val
                ste_Hsh.add(str(sudoku))
            else:
                tried.add(val)
                
                if(len(tried) == len(r[1][new_pos[1]])):
                    return (-1,-1)
            i+=1
        print("no of States :",noOfStates)      
        #remove from square
        r[0][locateSquareOfPos(new_pos,sudoku)].remove(val)
        #remove from col 
        r[1][new_pos[1]].remove(val)
        #remove from row
        r[2][new_pos[0]].remove(val)
                
        return (sudoku,r)
    except:
        return (-1,-1)

该算法在解决简单/中等问题时表现良好,但对于困难问题,它将永远持续下去。董事会的独特状态数量达到 100,000。

编辑:问题出在 findNewPos()。我的启发式不正确。

这是更新的版本:

def findNewPos(sudoku,r):
    new_pos = [-1,-1]
    no_r = 10
    deg_h = 100
    for i in range(sudoku.shape[0]):
        for j in range(sudoku.shape[1]):
            if sudoku[i][j] == 0:
                common = np.intersect1d(r[0][locateSquareOfPos([i,j],sudoku)]\,np.intersect1d(r[2][i],r[1][j]))
                if len(common) == 0:
                    return [-1,-1]
                if len(common) < no_r:
                    no_r = len(common)

                    deg_h = len(r[0][locateSquareOfPos(new_pos,sudoku)])\
                    +len(r[1][j]) + len(r[2][i])

                    new_pos = [i,j]
                    
                elif len(common) == no_r:

                    rmng = len(r[0][locateSquareOfPos(new_pos,sudoku)])\
                    +len(r[1][j]) + len(r[2][i])

                    if rmng < deg_h:
                        deg_h = rmng
                        new_pos = [i,j]

    return new_pos

现在所有数独都在解决,尽管速度很慢。我需要改进我的 tiebreaker 启发式(当有多个变量的剩余值相同时),并且我想使用度数启发式。但是,我不确定这在数独的上下文中会如何工作。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。