數獨求解

芬蘭一位數學家號稱設計出全球最難的“數獨遊戲”,並刊登在報紙上,讓大家去挑戰。這位數學家說,他所設計的數獨遊戲難度等級是十一,可以說是所有數獨遊戲中,難度最高的等級。

                                                                                  

 

編程求解的方法有兩種

窮舉法:窮舉法算法簡單,但運行時所花費的時間量大,這裏主要討論回溯法。

回溯法:按照深度搜索的方式進行。即在第一層選定一個滿足約束條件的解,然後以該可能解爲出發點,搜索第二層的一個可能解(試探)。如果搜索到第二層的一個可能解,則繼續搜索第三層的一個可能解。依次類推,直到所有層的可能解都被找到,則得到了該問題的一個完整解。如果第二層所有的可能解都不滿足約束條件,則返回第一層,放棄原有的可能解,使用第一層的下一個可能解(回溯)。以此類推,尋找第二層的一個可能解。


數獨問題的約束條件爲: 

l)數值範圍僅限於l一9。 

2)行中不允許重複數字。

3)列中不允許重複數字。 

4)小九宮內不允許重複數字。


此處僅僅考慮最簡單的場景,並沒有在性能上做優化。關於算法性能,老外有一篇文章講解的很棒 "Solving Every Sudoku Puzzle"

對應python代碼如下


class Suduko(object):

    def __init__(self, s):
        self.s = s 

    def check_all(self, i, j, value):
        #檢測s[i][j]=value時,是否滿足數獨約束
        return self.check_row(i, j, value) and self.check_column(i, j, value)\
               and self.check_small_sudoku(i, j, value)

    def check_row(self, i, j, value):
        #檢測s[i][j]=value是否滿足 行中不允許重複數字
        return value not in self.s[i]

    def check_column(self, i, j, value): 
        #檢測s[i][j]=value是否滿足 列中不允許重複數字
        column = [self.s[v][j] for v in range(9)] return value not in column

    def check_small_sudoku(self, i, j, value):
        #檢測s[i][j]=value是否滿足 小九宮格不允許重複數字
        small_sudoku = [self.s[m][n] for m in range(i/3*3,(i/3+1)*3)\ for n in range(j/3*3,(j/3+1)*3)]
        return value not in small_sudoku

    def recursion_search(self):
        #回溯求解,如果i,j都大於等於8,表示求解OK
        i,j = self.start_point()
        if i >=8 and j >=8 and self.s[8][8]:
            return True

        for value in range(1,10):
            if self.check_all(i, j, value):
                self.s[i][j] = value #如果s[i][j]滿足約束,則令s[i][j]=value
                if not self.recursion_search():
                    self.s[i][j] = 0 #如果後面的遞歸搜索不滿足要求,令s[i][j] = 0
                else:
                    return True
        return False #如果該點遍歷1-9都不符合要求,則表示上游選值不當,回溯 

    def start_point(self)“
        for i in range(9):
            for j in range(9):
                if not self.s[i][j]:
                    return i,j
        return i,j

if '__main__' == __name__:

    s = [[8,0,0,0,0,0,0,0,0],
         [0,0,3,6,0,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,7,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]]

    S = Suduko(s)

    S.recursion_search()

    for i in range(9):
        print S.s[i]


求解答案如下

[8, 1, 2, 7, 5, 3, 6, 4, 9]
[9, 4, 3, 6, 8, 2, 1, 7, 5]
[6, 7, 5, 4, 9, 1, 2, 8, 3]
[1, 5, 4, 2, 3, 7, 8, 9, 6]
[3, 6, 9, 8, 4, 5, 7, 2, 1]
[2, 8, 7, 1, 6, 9, 5, 3, 4]
[5, 2, 1, 9, 7, 4, 3, 6, 8]
[4, 3, 8, 5, 2, 6, 9, 1, 7]
[7, 9, 6, 3, 1, 8, 4, 5, 2]


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章