我正在用SML/NJ創建一個數獨求解器。我已經掌握了實際操作輸入數據的所有功能(檢查行的合法性,強制空白空間等),但是我在回溯部分遇到問題。具有回溯的SML中的數獨求解器
我碰到過this question但我很困惑如何在SML中實現它。
。注意,板被輸入作爲表示每一行,0中的數字對於一個未知點
[[0,0,0, 2,6,0, 7,0,1],
[6,8,0, 0,7,0, 0,9,0],
[1,9,0, 0,0,4, 5,0,0],
[8,2,0, 1,0,0, 0,4,0],
[0,0,4, 6,0,2, 9,0,0],
[0,5,0, 0,0,3, 0,2,8],
[0,0,9, 3,0,0, 0,7,4],
[0,4,0, 0,5,0, 0,3,6],
[7,0,3, 0,1,8, 0,0,0]]
這是我的(編輯)solve
功能列表的列表。
exception Sudoku;
fun solve board =
let fun solve' board k =
(* k is the row we are working on, so if it's 9, we SHOULD be done *)
if k = 9 then board else
let
(* get row k from the board *)
val row = (List.nth (board, k));
fun trySpot number col =
(* if number >= 10, raise an exception to backtrack *)
if number > (length row) then raise Sudoku
(* if col = 9, raise an exception to backtrack *)
else if col = 9 then raise Sudoku
(* if row[col] is not a zero, move to next col *)
else if not (List.nth(row, col) = 0) then trySpot number (col + 1)
(* row doesn't contain this num already *)
else if length (List.filter (fn x => x = number) row) = 0 then
let
(* build the new row and board and check if legal (this works fine) *)
val newRow = delete(col + 1, (insertAtPos row number col));
val newBoard = delete(k + 1, (insertAtPos board newRow k));
val isLegal = checkLegal newBoard;
in
(* if legal, keep solving with new board as base *)
if isLegal then
solve' (force newBoard) 0
handle Sudoku => solve' (force board) (k + 1)
(* not legal, try with next num *)
else trySpot (number + 1) col
end
(* row already has this number, skipping *)
else trySpot (number + 1) col
in
(* if board is complete and legal we're done *)
if completedBoard board andalso checkLegal board then board
(* if row has a zero then try a spot *)
else if (zeroInList row) then trySpot 1 0
(* otherwise move to next row *)
else solve' (force board) (k + 1)
end
in
(* initial solve *)
solve' (force board) 0
end;
調用上的採樣數據solve
上述返回以下列出
[[4,3,5,2,6,9,7,8,1],
[6,8,2,5,7,1,4,9,3],
[1,9,7,8,3,4,5,6,2],
[8,2,6,1,9,5,3,4,7],
[3,1,4,6,8,2,9,0,0],
[0,5,0,0,0,3,0,2,8],
[0,0,9,3,0,0,0,7,4],
[2,4,0,0,5,0,0,3,6],
[7,0,3,0,1,8,0,0,0]]
現在,這是部分正確。前四行看起來是完全正確的,這是基於我用來檢查的在線數獨求解器,但它會在第5行中搞砸。我認爲這是因爲它無法一路走回頭路。
它「備份」的唯一地方是在這條線
handle Sudoku => solve' (force board) (k + 1)
這告訴它只是試圖解決舊板(沒有新的號碼),但是,這是防止它回溯多於一步(我認爲)。這怎麼可能完成?
如果有人好奇,想看看完整的代碼,你可以找到它here.
提前感謝!
Hansen和Rischel編寫的書籍「使用SML進行編程」介紹了一個回溯算法的例子,用於解決使用異常實現的8皇后問題。我能夠修改他們的代碼來獲得騎士旅程,而沒有太多困難。它可能會給你一些想法(雖然現在我更可能使用選項而不是例外)。 –
感謝您的建議,我會看看 –
@JohnColeman,我看了他們的實現,並試圖修改我的求解函數來實現帶有異常的回溯。它在某種程度上起作用,但我不確定如何讓它進一步回到決策樹中。有任何想法嗎? –