對於數獨游戲的研究,我們不免要研究數獨游戲的完全解的生成算法,對於完全解的生成過程,我們一般是采用回溯法來產生整個九宮格的所有的數據。而對於九九八十一格的數獨游戲完整解生成,我們嘗試按常規的回溯方法來實現,不免會出現回溯的解空間過於龐大而導致回溯的時間過長而無法滿足游戲中我們產生游戲完全解的需要。為此,我們需要一種高效的完全解的生成算法,以滿足我們在數獨游戲中快速的產生完全解。對此,我們需要對數獨進行進一步的探索和研究。
那首先我們來了解一下數獨游戲,數獨的基本規則就是在如下圖所示的大九宮格中的九九八十一格里隨機填入1-9這九個數字中的任意一個,並且要保證每一橫行、豎行的九個數字沒有重復數字,還要保證每一個小九宮格中的九個數字也不能重復。如下圖,我們將每一個小九宮格塗上了不同的顏色以便於區分。
要生成合法的數獨完全解,那我們必須了解數獨完全解的所具有的特性。那我們下面看一組標准的數獨完全解的例子,如下所示我們看到一組數獨完全解(這是我們實現的算法生成的解)。
8 7 1 9 3 2 6 4 5
4 9 5 8 6 1 2 3 7
6 3 2 7 5 4 8 1 9
5 2 8 4 7 3 1 9 6
9 1 3 6 2 5 7 8 4
7 6 4 1 9 8 3 5 2
2 8 7 3 4 9 5 6 1
1 4 6 5 8 7 9 2 3
3 5 9 2 1 6 4 7 8
通過檢查,我們看到上面這一組解是滿足數獨規則的。但我們為了研究數獨完全解的特性,需要將這一組解放入九宮格中進行分析,如下圖我們將這一組解放入到九宮格,首先我們知道,整個大九宮格(九九八十一格)中我們只能填入數字1-9,而我們看到的是橫行、豎行和小九宮格都是九格,也就是說,我們在橫行、豎行和小九宮格都必須使用到這九個數字。
若我們要生成一組數獨完全解,那如果按傳統的回溯方法來產生,那我們首先會從第一個方格(從左至右,從上至下)開始,先從1-9九個數字中選取一個數字填入該處,然后我們再從第二個方格開始,選取八個數字(按數獨規則不能重復,則要除去剛剛填入的一個數字)中的一個,依此下去選填數字……當然后續方格中選擇的數字,都會因為數獨規則,使其所在橫行、豎行和小九宮格中,其他已填方格中的數字對該處可填入的數字產生不同的條件約束。某種情況下,我們可能發現填到某格時,由於數獨規則約束我們已經沒有數字可以填入該處了,這時候我們就要開始回溯了,撤銷上一步填入的數字,重新選擇一個數字填入上一步的方格,然后繼續開始本次的填數,若不行還得繼續回溯。有時會因為某種制約,導致我們要不停回溯撤銷重填。若按照這種思路做下去,我們發現由於解空間過於龐大,我們能生成合適的完全解可能要花比較長的時間。這樣的算法思路根本無法滿足我們快速產生完全解的需要。這時我們想到要去縮小回溯的解空間,讓回溯的解空間盡量的減小。
於是我們開始的新的算法探索,如下圖通過分析我們知道,1-9這九個數字一定都會被使用,而且是每一橫行、豎行和每一個小九宮格都會有1-9中的一個數字。首先我們來對整個大九宮格進行划分,我們將整個大九宮格划分為九個小九宮格。按從左至右,從上至下排序,也就是上面三個分別為1、2、3中間三個分別為4、5、6,而下面三個分別為7、8、9。那我們先填1-9這九個數字中的“1”,我們觀察下面圖例的解可以看到。在第一個小九宮格中填入一個“1”,在第二、三個小九宮格中也要填入一個“1”,而要滿足數獨規則,第二個小九宮格中填入的“1”就不能和第一個小九宮格的“1”在同一行,同時第三個小九宮格填入的數字“1”也不能和第一、二個小九宮格的“1”在同一行。以此類推下去,我們繼續填第四、五、六、七、八、九個小九宮格中的“1”,當第九個小九宮格數字“1”填完以后,整個過程完全可以不用回溯。那我們接着開始填入1-9這九個數字中數字“2”,在第一個小九宮格中我們除去之前填入數字“1”被占用的位置,其他的八個空的方格我們都是可以隨便填的,我們隨機選取其中的一個空格,填入數字“2”。填完后,我們接着填第二個小九宮格中的數字“2”,填入的位置要求還是要滿足數獨規則的,在這里由於我們在每個小九宮格中1-9中的每個數字都填過一次,所以這里完全不用考慮小九宮格的數字不重復的問題,所以考慮的就是,每一橫行、豎行是否滿足數獨規則,即填入的數字都不重復。這樣我們按照一定的順序依次在九個小九宮格中填入1-9這九個數字。當九個小九宮格的數字“9”填完。整個大九宮格九九八十一個數字填入完畢,那么符合數獨規則的完全解也就應運而生。當然這里也會有回溯的情況產生,當我們某個數字在填入某個小九宮格時,發現其可填空着的方格在橫行、豎行上都已有該數字,那么這時我們無法在此小九宮格填入該數字了,這時我們要回溯到上一個小九宮格中,撤銷這個小九宮格填入的該數字,重新選取可填位置填入該數字(這里不用選取數字,數字已選定)。填入完成后,再回到本次需要填入該數字的小九宮格中選填該數字。我們需要把1-9這九個數字中的每一個數字在九個小九宮格中按照數獨規則都填入一遍。當第9個小九宮格中數字“9”填入完成,數獨完全解也就生成了。
該算法采用分治的思想將整個大九宮格分為九個小九宮格,1-9九個數字按順序填入,排除了數字之間的限制約束,每個數字獨立填入的回溯空間大大縮小,某些數字甚至無需回溯,例如此過程中的數字“1”和“9”就不需要進行回溯。同時我們產生時結合隨機數選填位置,這樣能保在持數字之間很好的隨機性的同時,又在產生時間上極大的縮短了耗時。這樣思路實現的代碼產生出來的數獨完全解,計算機耗時基本保持在幾毫秒左右。就是以人工方式手動填入的方法,也可在幾分鍾之內產生一組合法的數獨完全解。此算法相較於傳統的回溯算法,其效率明顯的提高了很多。
為了便於區分我們將1-9這九個數字標識不同的顏色。填入完成后的解,如下圖所示。最后通過我們實現該算法的java代碼的實際測試,其產生10000組解的實際平均耗時為3.25秒左右。實際測試中我們使用的是筆記本,后台也有運行其他的軟件,我們有嘗試將測試數據調至10000000組,該次測試過程中CPU占用率平均在50%左右,筆記本有輕微發熱,最后耗時為52.98分鍾,當然這些測試中我們並沒有去驗證產生數獨完全解的唯一性,做這些測試只是為了驗證數獨完全解的產生速度。
轉自:http://blog.sina.com.cn/s/blog_a28e3dd90101e1i2.html