1. 程式人生 > >數獨的生成演算法和解題演算法

數獨的生成演算法和解題演算法

github專案地址:https://github.com/Xcodingman/sudo.git

配置環境:windows10 vs2013

開啟工程檔案,執行相對應的cpp檔案即可

1.數獨解題與出題演算法

一、基於遞歸回溯法的數獨解題演算法

思路:眾所周知,數獨一般的解法需要用到很多次的推導,對各行各列各個九宮格進行排查,刪選候選數後挑選候選數最少的去填。仿照這樣的思想,我們用C++模擬這樣的思路去解一個數獨。流程圖如下:

具體實現:

1.預處理

考慮到更好的表示數獨中19九個數字,我們採用一個9*9的二維陣列去表示一個數獨,它的每一個元素用一個9位的二進位制數表示,每一位的1表示這個位置序號在侯選數組裡面,具體如下表格所示。預處理函式(程式碼中的

init函式)的作用是把輸入的數獨矩陣進行轉換,如果是0,則換成0x1FF,表示所有數字均有可能,如果有確定值的,則按確定值的大小轉換為二進位制中只有一位116進位制數。

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數量級的數獨,本程式採用對數獨矩陣的簡單變換來產生大約數量級在

10^6左右。

   首先程式內建一個已經解好的數獨,建立一個一維陣列,裡面存放1-9的九個數字,用這個陣列的下標號加一對應數獨裡面的數字,並把該下標的元素與對應數獨的元素進行轉換,例如,一維陣列為{9,8,7,6,5,4,3,2,1},則把數獨裡面的9全部換成18全部換成2……以此類推,這樣,根據產生的一維數組裡面九個數字的順序不同,可能變換得到9=3628800個不同的完整數獨。

2.挖空

對產生的完整數獨進行挖空,挖空演算法根據隨機數隨機挖空,不同難度對應不同的隨機挖空概率。

3.檢查是否滿足要求

對上述挖好空的數獨用之前的解數獨演算法進行解,如果有多解則放棄該數獨,重新產生新的數獨。若有唯一解,則繼續檢視該數獨的難度,難度有三個影響因素:

1.解數獨時的顯性推導,即通過侯選數刪選以後發現只有一個侯選數。

2.解數獨時的隱性推導,即該位置有多個侯選數,只能通過猜測來填該位置。

通過三個因素的不同權重大小(顯性推導權重較小,隱性推導權重較大),計算中一個難度值,不同難度選擇對應不同的難度值。