經典算法之八皇后問題

八皇后問題是一個古老而又著名的問題,是學習回溯算法的一個經典案例。今天咱們就一塊兒來探究一下吧!算法

file

時間退回到1848年,國際西洋棋棋手馬克斯·貝瑟爾提出了這樣的一個問題,編程

在8×8格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問一共有多少種擺法。

後面陸續有不一樣的學者提出本身的看法。大數學家高斯認爲一共有76種擺法,1854年在柏林的象棋雜誌上不一樣的做者發表了共計40種不一樣的看法,後來還有人利用圖論的方法得出共有92種擺法。segmentfault

而現在,經過咱們的計算機以及編程語言咱們能夠輕鬆的解決這個問題。數組

最直接的也是最容易想到的一種解法即是暴力法,咱們能夠在8×8的格子中任選8個皇后,選定後看是否知足任意兩個皇后都不處於同行同列同斜線的條件,若知足則累計知足條件的方案。學習過排列組合的咱們發現64取8這個數字達到了40億,顯然是使人難以接受的。編程語言

file
但咱們根據這個條件,咱們能夠人爲地作出一些選擇,好比根據條件咱們可知每行每列最多都只能有一個皇后,這樣能夠在必定程度上縮減問題的規模。在第一行的某一列選擇放置一個皇后,共有8種不一樣的選擇,而第二行只能選擇剩下的7列,也就是7種選擇,剩下每一行的選擇都會遞減1,那麼總共可供選擇的方案有8的階乘種,已是一種遠優於暴力解法的解法,可是這個階乘的時間複雜度恐怕也難以使人接受,還有更優的解法嗎?函數

file

那是天然的,這即是遞歸回溯的方法。學習

當咱們選擇了第一個皇后的位置以後,與其處於同行同列同斜線的位置便都沒法被選擇,第二個皇后只能放在未被第一個皇后所輻射到的位置上,接着放置第三個皇后,一樣不能放在被前兩個皇后輻射到的位置上,若此時已經沒有未被輻射的位置可以被選擇,也就意味着這種擺法是不可行的,咱們須要回退到上一步,給第二個皇后從新選擇一個未被第一個皇后輻射的位置,再來看是否有第三個皇后能夠擺放的位置,如仍是沒有則再次回退至選擇第二個皇后的位置,若第二個皇后也沒有更多的選擇則回退到第一個皇后,從新進行位置的選擇。spa

file

總體的方法便如上所述,下面用直觀的代碼來實現這個算法,code

def find_Queen(row):

    if row>7:
        global count
        count+=1
        print_queen()
        return
    
    for column in range(8):
        if check(row,column):
            Queen[row][column]=1
            find_Queen(row+1)
            Queen[row][column]=0

定義一個二維數組Queen,數組中相應位置爲1則表示該位置放置皇后,按行來擺放皇后的位置,若是當前選擇無法繼續往下找到皇后的放置位置,則將以前置爲1的從新置爲0,也就是回退。而check函數的主要目的是爲了篩選皇后的合適位置以知足條件。具體能夠分爲三塊,行列檢查,主對角線以及負對角線檢查。blog

def check(row,column):
    
    # 檢查行列
    for k in range(8):
        if Queen[k][column]==1:
            return False
        
    # 檢查主對角線    
    
    for i,j in zip(range(row-1,-1,-1),range(column-1,-1,-1)):
        if Queen[i][j]==1:
            return False   
        
    # 檢查副對角線     
    for i,j in zip(range(row-1,-1,-1),range(column+1,8)):
        if Queen[i][j]==1:
            return False          

    return True

當已經放置了八個皇后時,進入 if 語句,累計數值而且打印出相應的皇后擺放示意圖。

file

實體的星星表示當前位置擺放了皇后,而具體的打印代碼以下所示,

def print_queen():
    
    print(Queen)
    for i in range(8):
        for j in range(8):
            if Queen[i][j]==1:
                print('☆ '*j+'★ '+'☆ '*(7-j))
    print("\n\n")

這樣,經過遞歸回溯的辦法,咱們找到了八皇后的92種解,而且以形式化的方法打印了出來。經過對八皇后問題的學習,咱們能夠深入體會到回溯的思想~

相關文章
相關標籤/搜索