【问题标题】:How to fix my sudoku solver based on backtracking如何基于回溯修复我的数独求解器
【发布时间】:2018-10-16 08:03:12
【问题描述】:

我尝试使用 python 并基于回溯创建一个数独求解器算法,但它始终没有返回任何内容表明数独不正确。

这是我的代码:

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

e = [0, 0]

def checkEmpty():
    for i in range(0, 9):
        for j in range(0, 9):
            if board[i][j] == 0:
                e[0] = i
                e[1] = j
                return True
    return False

def vLine(i, test):
    for j in range(9):
        if board[i][j] == test:
            return True
    return False

def vColumn(j, test):
    for i in range(9):
        if board[i][j] == test:
            return True
    return False

def vBlock(i, j, test):
    for I in range(3):
        for J in range(3):
            if(board[i+I][j + J] == test):
                return True
    return False

def validMove(i, j, test):
    if vColumn(j, test) == False and vBlock(i, j, test) == False and vLine(i, test) == False:
        return True
    else:
        return False

def solve():
    e = [0, 0]
    if checkEmpty() == False:
        return True
    i = e[0]
    j = e[1]
    for k in range(1, 10):
        if validMove(i, j, k) == True:
            board[i][j] = k
            if solve() == True:
                return True
            board[i][j] = 0
    return False

if solve():
    print("solved!")
else:
    print("No solution exists")

问题在于 if 函数 if validMove(i, j, k) == True: 中的代码似乎永远不会被执行。 但是我在这个函数中找不到任何错误。

另外,我真的不知道我应该缩进,缩进还是保留这行board[i][j] = 0在这里。

【问题讨论】:

    标签: python python-3.x recursion backtracking


    【解决方案1】:

    您的块检查器是错误的 - 如果您输入 2,2,9 它不会检查正确的块,而是一些未对齐的东西。

    def vBlock(i, j, test):
        for I in range(3):
            for J in range(3):
                if(board[i+I][j + J] == test):   # checks 2-5. 2-5 row&col
                    return True
        return False
    

    改成

    def vBlock(i, j, test):
        for I in range(3):
            for J in range(3):
                if(board[i//3+I][j//3 + J] == test): # this way it cecks the blocks correctly 
                    # if you input 2,2,9 it checks 2//3+range == 0+0-3 
                    return True
        return False
    

    这不会改变整体误差,但至少会补偿一个误差。


    您递归到solve(),而无需更改当前检查的行/列的e-列表-您的solve()适用于本地变量e-您的checkEmpty()更改全局 e,更改不会反映在 solve() 中。

    修复:

    def checkEmpty():
        global e        # explicitly use the global e
        for i in range(0, 9):
            for j in range(0, 9):
                if board[i][j] == 0:
                    e[0] = i
                    e[1] = j
                    return True
        return False
    
    def solve():
        global e        # explicitly use the global e
        if checkEmpty() == False:
            return True
        i = e[0]
        j = e[1]
        print(e)
        for k in range(1, 10): 
            if validMove(i, j, k) == True:
                board[i][j] = k
                if solve() == True:
                    return True
                board[i][j] = 0
    
        return False
    

    即使你修复了这两个错误:

    您需要能够丢弃较早的发现- f.e.在开始时,一个空间可能能够被 9、1、3、4 填充——你先检查 1——宾果游戏——把它放进去,但后来在这个块中只能容纳 1 的地方遇到了问题。现在 1 被放弃了,你没有解决方案。

    您需要首先计算所有0 的“所有可能”数字,然后填写只有一种可能性的数字,从相应的行/列/块0 可能性列表中删除该数字并继续直到所有已填写。

    底线:使用可用的第一个选择来解决它可能会以解决 12 个剩余零中的 10 个的局部最小值结束,然后你就被卡住了。

    【讨论】:

    • 但是,即使我的程序目前没有得到很好的优化,它至少应该找到解决方案(我猜在很长一段时间内)但是,我仍然遇到同样的问题。我想如果我想获得一个有效的求解器,我将不得不直接跳到你提到的修复良好的优化...非常感谢你的帮助!
    猜你喜欢
    • 2023-03-27
    • 2017-12-16
    • 1970-01-01
    • 1970-01-01
    • 2014-02-07
    • 1970-01-01
    • 2021-12-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多