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)>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, row=0):
if row == len(board):
return board
else:
for col in range(len(board[row])):
if board[row][col] == 0:
for number in range(1, len(board)+1):
board[row][col] == number
if isLegalSudoku(board) == True:
solution = solveSudoku(board, row+1)
if solution != None:
return solution
board[row][col] == 0
return None
测试代码:
def testSolveSudoku():
print('Testing solveSudoku()...', end='')
Board = [
[1, 0, 3, 0],
[4, 3, 0, 1],
[2, 0, 1, 0],
[0, 0, 4, 2]
]
Sol = [
[1, 2, 3, 4],
[4, 3, 2, 1],
[2, 4, 1, 3],
[3, 1, 4, 2]
]
print(solveSudoku(Board))
assert(solveSudoku(Board) == Sol)
print('Passed!')
*正如名字所暗示的,isLegalValues 接受一个列表,如果该列表包含合法值,则返回,也就是说,该列表不能有非零数字的重复,0 可以工作。isLegalRow 和 isLegalCol 遍历数独板并建立一个包含特定行/列值的列表并将它们插入 isLegalValues。isLegalBlock 找到板子中的块,并获取一个块号并将其插入 isLegalValues。(通过广泛的测试,这些似乎都有效)
我目前遇到的问题是,由于某种原因,我的代码完成了解决难题,但设法完成了运行。例子:
[1, 2, 3, 0],
[4, 3, 2, 1],
[2, 4, 1, 0],
[3, 0, 4, 2]
应该改为
[1, 2, 3, 4],
[4, 3, 2, 1],
[2, 4, 1, 3],
[3, 1, 4, 2]
但我一直返回上面 2 行的代码。(带 0 的那个)
似乎部分代码正在工作,因为所有被替换的值都是有效的,但回溯似乎有问题。我想知道是否有人可以指出出了什么问题,我该如何解决?
谢谢
解决方案
基本上,我犯了一个错误,我不断地用这段代码跳过同一列中的值,并且也从未尝试解决最后一列。
解决方案:
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
这完成了任务,虽然有点慢,首先检查整个电路板是否有 0(基本情况),然后循环遍历电路板中的所有值,如果值为 0,则测试所有可能的值(合法)数字。然后它检查整个董事会是否合法,然后继续。如果有错误,它会回溯。如果没有解决方案,则返回 None。
推荐阅读
- c - 我应该在信号处理程序中放入什么以使其终止除父进程之外的所有进程?
- facebook - 为什么不能用 nativescript-facebook 初始化 facebook
- java - 测试休眠方法时,Mockito 总是返回 NULL
- azure - 在 Azure Blob 存储中添加自定义域
- git - 在构建过程中下载 Azure DevOps 中的辅助存储库
- php - 在 Laravel 中,如何在不使用(队列和作业)的情况下从控制器异步发送电子邮件?
- android - Android - Espresso 如何在单击并移动到另一个 Activity 后测试视图
- javascript - 当我尝试将对象推入 jquery 中的数组时,我得到了这种类型的数组
- cdn - 多个 CDN 会加速页面加载吗
- javascript - 我可以使用变量作为标识符来设置私有类字段吗?如何?