數獨的生成演算法和解題演算法
github專案地址:https://github.com/Xcodingman/sudo.git
配置環境:windows10 vs2013
開啟工程檔案,執行相對應的cpp檔案即可
1.數獨解題與出題演算法
一、基於遞歸回溯法的數獨解題演算法
思路:眾所周知,數獨一般的解法需要用到很多次的推導,對各行各列各個九宮格進行排查,刪選候選數後挑選候選數最少的去填。仿照這樣的思想,我們用C++模擬這樣的思路去解一個數獨。流程圖如下:
具體實現:
1.預處理
考慮到更好的表示數獨中1到9九個數字,我們採用一個9*9的二維陣列去表示一個數獨,它的每一個元素用一個9位的二進位制數表示,每一位的1表示這個位置序號在侯選數組裡面,具體如下表格所示。預處理函式(程式碼中的
16進位制2進位制侯選數
0x1000000001確定值1
0x2000000010確定值2
0x77001110111侯選值123567
0x1FF111111111侯選值123456789
2.遞歸回溯
第一步:遍歷預處理過的矩陣的每一個元素,通過對行,列以及周圍格子的檢查,得出該位置所有可能的侯選數值。
第二步:通過一個check函式去檢查更新過的數獨的結果,有三種情況。
1.數獨已經被全部填完並正確。
2.數獨還有空未填。
3.該數獨不滿足規則。
第三步:根據上述check的情況,分別對應三種情況:
1.先把此次答案打印出來,然後返回上一次遞迴繼續解題,檢視是否有多解。
2.選取未填的格子裡面侯選數最少的一個格子選填一個侯選值,執行第二步。
3.退出當前的嘗試,返回上一次遞歸併換下一個可能的侯選值。
3. 結束
所有的嘗試結束後,遞迴程式退出,並顯示用時。
二、出題演算法
1.該題只有一個解
2.每一次的題目都不一樣
3.難度可選
思路:數獨的出題很難用正向思維去出,所以本程式採用了反向思維去出題,本程式先產生一個數獨題,然後去上述的解數獨演算法去解,若滿足條件則程式結束,若不滿足則繼續嘗試下一個數獨題目。流程圖如下:
1.產生完整數獨
考慮到數獨數量的巨大,據統計大約有6.671*10^21數量級的數獨,本程式採用對數獨矩陣的簡單變換來產生大約數量級在
首先程式內建一個已經解好的數獨,建立一個一維陣列,裡面存放1-9的九個數字,用這個陣列的下標號加一對應數獨裡面的數字,並把該下標的元素與對應數獨的元素進行轉換,例如,一維陣列為{9,8,7,6,5,4,3,2,1},則把數獨裡面的9全部換成1,8全部換成2……以此類推,這樣,根據產生的一維數組裡面九個數字的順序不同,可能變換得到9!=3628800個不同的完整數獨。
2.挖空
對產生的完整數獨進行挖空,挖空演算法根據隨機數隨機挖空,不同難度對應不同的隨機挖空概率。
3.檢查是否滿足要求
對上述挖好空的數獨用之前的解數獨演算法進行解,如果有多解則放棄該數獨,重新產生新的數獨。若有唯一解,則繼續檢視該數獨的難度,難度有三個影響因素:
1.解數獨時的顯性推導,即通過侯選數刪選以後發現只有一個侯選數。
2.解數獨時的隱性推導,即該位置有多個侯選數,只能通過猜測來填該位置。
通過三個因素的不同權重大小(顯性推導權重較小,隱性推導權重較大),計算中一個難度值,不同難度選擇對應不同的難度值。