假設我有一個數獨陣列,在數獨解算器中使用,例如:
[[0 0 0 0 0 0 0 5 0]
[2 0 7 0 0 9 0 0 0]
[6 0 0 3 5 1 0 0 0]
[5 0 0 0 0 0 0 1 0]
[0 0 3 0 0 0 0 0 8]
[0 0 0 8 2 0 5 3 0]
[0 0 0 0 7 0 8 0 4]
[0 0 6 2 0 0 0 0 0]
[0 8 0 0 0 0 7 0 0]]
我有一個方法nextMove(),目前它回傳解算器要檢查的下一個坐標。
當前的實作是:
for x in range(9)。
for y in range(9)。
if sudoku[x][y] == 0:
return [x,y] 。
在閱讀Norwigs關于演算法的書時,我偶然發現了消除策略,我想嘗試在求解器中應用。我的基本想法是檢查哪一行 哪一列的組合的可能性最小(周圍的數字最多)
。我已經嘗試了:
def next_move(sudoku)。
row = 0.
current_number_row = 0: row = 0.
current_number_column = 00
max_num_col = 0
max_num_row =0
for x in range(9)。
current_number_row = 0.
for y in range(9)。
if sudoku[x][y] != 0:
current_number_row = 1 :: current_number_row = 1
if current_number_row > max_num_row and current_number_row < 9:
max_num_row = current_number_row
行 = x
for m in range(9)。
current_number_column = 0.
if sudoku[row][m] == 0:
for g in range(9)。
if sudoku[g][m] != 0:
current_number_column = 1 :: current_number_column = 1
if current_number_column > max_num_col and current_number_column < 9:
max_num_col = current_number_column
列=m
return [row, column] (行,列)
然而,這并不奏效,因為有時演算法會不斷回傳相同的位置,盡管它已經被填滿了。
我如何撰寫消除策略以提高性能,同時還能解決數獨問題?
uj5u.com熱心網友回復:
為了使這個消除策略有效,你需要有一個資料結構,在你走棋的程序中跟蹤鄰居的情況。 每次為每個位置重新計算都會使事情變得緩慢,而不是提高性能。
這樣的結構可以是一組不沖突的數字,在進行移動后,這些數字在每個位置都是可用的,也可以是要排除的沖突數字。 當你進行移動或收回時,你還需要使更新這個結構盡可能的有效。 這可以通過創建第二個結構來實作,該結構將每個位置映射到當數字放在那里時需要更新的位置。
除此之外,由于每個位置可以在3個維度上發生沖突(垂直、水平和區塊),你需要3個不同的組來處理集合中鄰居的加/減法。 因此,每個放置在特定位置的數字都必須在組的基礎上使其他位置無效。
下面是一個使用這種排除法的數獨解算器的小版本:
def shortSudokuSolve(board)。 #期望有一個串列作為棋盤。
size = len(board)
block = int(size**0.5)
board = [n for row in board for n in row ]
span = { (n,p): { (g,n) for g in (n>0)*[p//size, size p%size。
2*size p%size//block p/size//block*block] }
for p in range(size*size) for n in range(size 1) }
empties = [i for i,n in enumerate(board) if n==0 ]
used = set()。 union(*(span[n,p] for p,n in enumerate(board) if n)
empty = 0)
while empty>=0 and empty<len(empties)。
pos = empties[empty]
used -= span[board[pos],pos)
board[pos] = next((n for n in range(board[pos] 1, size 1)
if not span[n,pos]&used),0)
used |= span[board[pos],pos)
empty = 1 if board[pos] else -1
return [board[r:r size] for r in range(0,size*size,size)]
輸出:
test = [ [8,0, 0。0,0,0,0,0】。]
[0,0,3, 6。 0,0, 0,0] 。
[0,7,0, 0。 9,0, 2,0,0】。]
[0,5,0, 0, 0,7, 0,0,0] 。
[0,0,0, 0。 4,5, 6,0,0】。]
[0,0,0, 1, 0,0, 0,3, 0] 。
[0,0,1, 0, 0,0, 0,6,8】。]
[0,0,8, 5。 0,0, 0,1, 0] 。
[0,9,0, 0。 0,0, 4,0,0]
]
solution = shortSudokuSolve(test)
printSudoku(test,solution)
╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗ ╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
║ 8 │ │ ║ │ │ ║ ║ 8 │ 1 │ 2 ║ 7 │ 5 │ 4║ 3 │ 9 │ 6 ║
║ │ │ 3 ║ 6 │ │ ║ │ │ ║ ║ 9 │ 4 │ 3║ 6 │ 8 │ 2║ 1 │ 5 │ 7 ║
║ │ 7 │ ║ │ 9 │ ║ 2 │ │ ║ 6 │ 7 │ 5║ 3 │ 9 │ 1║ 2 │ 8 │ 4║
║ │ 5 │ ║ │ 7 ║ │ ║ ║ 1 │ 5 │ 6 ║ 9 │ 3 │ 7║ 8 │ 4 │ 2 ║
║ │ ║ │ 4 │ 5 ║ 6 │ │ ║ 3 │ 8 │ 9║ 2 │ 4 │ 5║ 6 │ 7 │ 1║
║ │ ║ 1 │ │ ║ │ 3 │ ║ 7 │ 2 │ 4 ║ 1 │ 6 │ 8║ 9 │ 3 │ 5 ║
║ │ │ 1 ║ │ │ ║ │ 6 │ 8║ 2 │ 3 │ 1║ 4 │ 7 │ 9║ 5 │ 6 │ 8║
║ │ 8 ║ 5 │ │ ║ │ 1 │ ║ 4 │ 6 │ 8║ 5 │ 2 │ 3║ 7 │ 1 │ 9║
║ │ 9 │ ║ │ 4 │ ║ ║ 5 │ 9 │ 7 ║ 8 │ 1 │ 6║ 4 │ 2 │ 3 ║
注意,這只是一個機械的說明,雖然它可以快速解決9x9的數獨謎題,但要在合理的時間內處理16x16或更大的數獨,還需要對數字選擇進行更微妙的排除/優先排序。
我確實有一個優化版本的解題器(太大,不能在此分享),它可以確定空單元格的優先級,早期檢測出死胡同(任何位置的所有數字都被排除在外,組的選項比空單元格少),并自動放置單個數字選項。 那個可以在一秒鐘內解決16x16的謎題,并且可以在大約一分鐘內處理一些36x36的謎題。
下面是我用于輸出的
標籤: 上一篇:當試圖用python匯入資料時,找不到我的Firebase實時資料庫。
下一篇:從多個陣列中找出最大和最小的K值
printsudoku函式:def niceSudo(board)。
side = len(board)
base = int(side**0.5)
def expandLine(line)。
return line[0] line[5:9] 。 join([line[1:5]*(base-1)]*base) line[9:13]
line0 = expandLine("╔╥﹏╥")
line1 = expandLine("║ . │ . ║ . ║")
line2 = expandLine("╟──┼──╫──╢")
line3 = expandLine("╠═══╪═══╬══╣")
line4 = expandLine("╚════╧══════╝")
symbol = " 123456789" if base < = 3 else " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
nums = [ [""] [symbol[n] for n in行] for row in board ]
lines = []
lines.append(line0)
for r in range(1,side 1) 。
lines.append( "". join(n s for n,s in zip(nums[r-1],line1.split(" 。" /span>)) )
lines.append([line2,line3,line4][(r%side==0) (r
