[英]Backtracking algorithm that finds solutions for sudoku
我正在研究算法的理論及其可能的解決方法。在這種情況下,我存在一些回溯問題。 我想寫一個填充數獨的函數 。 但它不會打印任何內容。 錯誤在哪里? 函數defsett(i,j)將兩個數字作為所選數字的坐標作為輸入,並設置兩個整數(w和o)作為輸入數字的3x3部分的起點。 取而代之,數獨功能會遞歸地嘗試用數獨規則填充矩陣。
# defsett = returns the coordinates of the first cell of the section 3x3
# where is the cell [i,j]
def defsett(i,j):
if(0<=i<=2):
if(0<=j<=2):
return (0,0)
elif(3<=j<=5):
return (0,3)
elif(6<=j<=8):
return (0,6)
elif(3<=i<=5):
if(0<=j<=2):
return (3,0)
elif(3<=j<=5):
return (3,3)
elif(6<=j<=8):
return (3,6)
else:
if(0<=j<=2):
return (6,0)
elif(3<=j<=5):
return (6,3)
elif(6<=j<=8):
return (6,6)
M = [[5,3,0,0,7,0,0,0,0],
[6,0,0,1,9,5,0,0,0],
[0,9,8,0,0,0,0,6,0],
[8,0,0,0,6,0,0,0,3],
[4,0,0,8,0,3,0,0,1],
[7,0,0,0,2,0,0,0,6],
[0,6,0,0,0,0,2,8,0],
[0,0,0,4,1,9,0,0,5],
[0,0,0,0,8,0,0,7,9]]
# n = matrix side
# i = index of rows
# j = index of cols
def sudoku(n,i,j,M):
if(i==n):
print(M)
elif(j==n):
j=0
i=i+1
sudoku(n,i,j,M)
else:
if(M[i][j]==0):
for number in range(1,n+1):
xInRows = False
xInCols = False
xInSection = False
# checking if number already present in this row
for k in range(n):
if (number == M[i][k]):
xInRows = True
# checking if number already present in this cols
for k in range(n):
if(number == M[k][j]):
xInCols = True
w,o=defsett(i,j) # first cell of this section
# checking if number already present in this section 3x3
for t in range(w,w+3):
for b in range(o,o+3):
if(number == M[t][b]):
xInSection = True
if(not(xInRows) and not(xInCols) and not(xInSection)):
M[i][j] = x
sudoku(n,i,j+1,M)
else:
sudoku(n,i,j+1,M)
sudoku(9,0,0,M)
-----
For this input works:
M = [[5,3,0,0,7,0,0,0,0],
[6,0,0,1,9,5,0,4,8],
[1,9,8,3,4,2,5,6,7],
[8,5,9,7,6,1,4,2,3],
[4,2,6,8,5,3,7,9,1],
[7,1,3,9,2,4,8,5,6],
[9,6,1,5,3,7,2,8,4],
[2,8,7,4,1,9,6,3,5],
[3,4,5,0,8,6,1,7,9]]
For this doesn't:
M = [[5,3,0,0,7,0,0,0,0],
[6,0,0,1,9,5,0,0,8],
[1,9,8,3,4,2,5,6,7],
[8,5,9,7,6,1,4,2,3],
[4,2,6,8,5,3,7,9,1],
[7,1,3,9,2,4,8,5,6],
[9,6,1,5,3,7,2,8,4],
[2,8,7,4,1,9,6,3,5],
[3,4,5,0,8,6,1,7,9]]
關於什么都不打印的原因很簡單: sudoku()
進行得不夠快,以至於i == 9
都無法得出True
。 因此,讓我們分析一下如何發生...
i == 9
9⇒退出解決方案 i != 9 and j == 9
9⇒下一行遞歸; sudoku(9, i+1, 0, M)
i != 9 and j != 9
M[i][j] != 0
0⇒與下一列sudoku(9, i, j+1, M)
遞歸sudoku(9, i, j+1, M)
M[i][j] == 0
0⇒嘗試擬合一個數字
number
⇒設置M[i][j] = number
( 不是 M[i][j] = x
),然后與下一列sudoku(9, i, j+1, M)
遞歸 這就是整個決策過程。 一旦sudoku()
退出,這就是M
:
[[5, 3, 2, 6, 7, 8, 9, 4, 0],
[6, 0, 0, 1, 9, 5, 0, 0, 8],
[1, 9, 8, 3, 4, 2, 5, 6, 7],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 8, 5, 3, 7, 9, 1],
[7, 1, 3, 9, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 4, 1, 9, 6, 3, 5],
[3, 4, 5, 0, 8, 6, 1, 7, 9]]
為了理解問題出在哪里,想象一下您在第8列中放入4之后調用了sudoku(9, 0, 8, M)
...
1是尚未在此行中放置的唯一數字,但是在此禁止使用,因為它已經出現在第五行( M[4][8]
)中。 sudoku(9, 0, 8, M)
退出,因為沒有其他可嘗試的數字。 由於沒有人能夠將1放置在其他任何地方,因此控制從這里移到調用堆棧中。 為什么1如此重要? 因為所有其他數字已經放在此行的某個位置,並且在sudko()
回溯時不會改變!
解決方法很簡單:在遞歸步驟后的一行中添加一個數字,以撤消所做的更改以進行適當的回溯。
(...)
if(not(xInRows) and not(xInCols) and not(xInSection)):
M[i][j] = x
sudoku(n,i,j+1,M)
M[i][j] = 0
(...)
僅此一項就可以使sudoku()
完成給定的M
我不能保證它將為任何M
找到解決方案。 ;-)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.