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

Sudoko求解器回溯算法不起作用 问题说明快速但丑陋的解决方案好的解决方案

如何解决Sudoko求解器回溯算法不起作用 问题说明快速但丑陋的解决方案好的解决方案

我对编程还很陌生,最近我开始研究sudoko求解器,除了求解算法本身之外,其他一切都很好,我从互联网上获得了一些帮助,但是由于我自己编写了方法,所以我可以找不到我的代码的准确解决方案,任何帮助将不胜感激!

问题:代码一直运行到无法将值输入到空(0)索引之一中为止,而不是回溯,它只是停止了。

如果您可以让我知道我在做错什么,或者提出可能的方法来改进代码,那么任何事情都会有很大帮助!

我的代码在这里

    import time
    start_time = time.time()

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


    def printBoard():
        print("Suduko Board")
        for row in grid:
            for elem in row:
                print(elem,end=' ')
            print()

    def checkInRow(grid,row,num):
        for i in range(0,9):
            if(grid[row][i] == num):
                return True
        return False

    def checkInCol(grid,col,9):
            if(grid[i][col] == num):
                return True
        return False

    def checkInBox(grid,num):
        #This will give the starting point for the Box
        BoxX = (row // 3) * 3
        BoxY = (col // 3) * 3   
        for i in range(3):
            for j in range(3):
                if((grid[BoxY + j][BoxX + i]) == num):
                    return True
        return False

    def findNextEmpty(grid,num):
        for row in range(9):
            for col in range(9):
                if(grid[row][col] == num):
                    return row,col
        return None


    def checkSafe(grid,num): #Returns true if safe returns false if unsafe
        return not checkInRow(grid,num) and not checkInCol(grid,num) and not checkInBox(grid,num)


    #PROBLEM IS HERE \/ 

    def solveSudoko(grid,i,j):
        if not findNextEmpty(grid,0):
            return True
        else:
            i = findNextEmpty(grid,0)[0] # Finds Row #
            j = findNextEmpty(grid,0)[1] # Finds Col #
            print(i,j)
            for value in range(1,10):
                if checkSafe(grid,j,value) == True:
                    grid[i][j] = value

                    printBoard()
                    print("--- %s seconds ---" % (time.time() - start_time))

                    if(solveSudoko(grid,j)):
                        return True

                    grid[i][j] = 0

            return False



    #print(str(value) + " can go in grid[" + str(i) + "]" + "[" + str(j) + "]")


    printBoard()

    solveSudoko(grid,0)

解决方法

问题说明

我认为问题在于您的网格是一个列表,即是可变的。这意味着,如果您调用solveSudoko(grid,i,j),则它不会复制网格,但是内存中只有一个网格。因此,solveSudoko遇到问题后便无法回滚,因为您已经更改了原始网格。可能的解决方案是使用不可更改的数据类型(例如元组或有点难看),但也可能是复制网格。

示例:

grid = [1,2,3]
def test(grid):
    grid[0] = 0
test(grid)
print(grid)
---> [0,3]

快速但丑陋的解决方案

您可能可以避免在代码开头添加import copy并替换

                    if(solveSudoko(grid,j)):

作者

                    if(solveSudoko(copy.deepcopy(grid),j)):

示例:

grid = [1,3]
def test(grid):
    grid[0] = 0
test(copy.deepcopy(grid))
print(grid)
---> [1,3]

请注意,在示例中也可以使用copy.copy而不是copy.deepcopy,因为整数是不可变的,但是如代码中所示,列表是列表,您需要copy.deepcopy

好的解决方案

示例:

grid = (1,3)
def test(grid):
    grid = (0,3)
test(grid)
print(grid)
---> (1,3)

元组的问题是获得新的网格并不有趣。我可能会使用一个小类来为我管理网格:

class Grid:
    def __init__(self,grid):
        assert type(grid) == tuple
        self.grid = grid

    @staticmethod
    def gird_from_list(list_):
        return Grid(tuple(list_[i][j] for i in range(len(list_)) for j in range(len(list_[0]))))

    def __repr__(self):
        return "\n".join(str(self.grid[i*9:(i+1)*9]) for i in range(9))

    def set(self,j,value):
        return Grid(tuple(value if i+j*9==k else x for k,x in enumerate(self.grid)))

tuple_grid = Grid.gird_from_list(gird)
tuple_grid2 = tuple_grid.set(8,8,0)

这里grid_from_list只是将您的列表转换为我的格式,而__repr__给您一个2d网格的漂亮表示,尽管我实际上只保留了1d元组。如果您不知道在打印类的实例时总是调用__repr__

现在打印tuple_grid将产生

(7,4,1,0)
(6,7,5,9)
(0,6,8)
(0,0)
(0,9,3,0)
(9,5)
(0,2)
(1,7)

打印出tuple_grid2将会产生

(7,0)

因此,在调用set时,围带不会改变,但会为您提供一个具有新值的全新围带。

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