8皇后問題(java算法實現)

最近總是無法靜下心來集中精神幹一些該乾的事情,百般空虛之下,總得找了點有意義的東西填充一下,找了一道很久以前就聽說挺經典的算法基礎題來研究,就是下面那道題了,有一句話不知道怎麼說來着,檢驗知識掌握與否的標準就在於你是否能把它清晰的傳達出來。老實說,把整個思路寫出來確實可以加深這個東西的理解。不過感覺現在的狀態很欠揍,盡幹這些東西來麻痹自己和打發時間。

 

   

       八皇后問題是一個古老而著名的問題,是回溯算法的典型例題。該問題是十九世紀著名的數學家高斯1850年提出:在8X8格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法。

  高斯認爲有76種方案。1854年在柏林的象棋雜誌上不同的作者發表了40種不同的解,後來有人用圖論的方法解出92種結果。現代教學中,把八皇后問題當成一個經典遞歸算法例題。

                      

                                                                                                                                                           —— 引用自百度百科
     國際象棋棋盤                                                     8皇后可行方案之一

                    圖1 國際象棋棋盤                                                                             圖2 一種可行的8皇后擺放方案

     

 

     首先,可歸納問題的條件爲,8皇后之間需滿足:

             1.不在同一行上

             2.不在同一列上

             3.不在同一斜線上

             4.不在同一反斜線上

 

     這爲我們提供一種遍歷的思路,我們可以逐行或者逐列來進行可行擺放方案的遍歷,每一行(或列)遍歷出一個符合條件的位置,接着就到下一行或列遍歷下一個棋子的合適位置,這種遍歷思路可以保證我們遍歷過程中有一個條件是絕對符合的——就是下一個棋子的擺放位置與前面的棋子不在同一行(或列)。接下來,我們只要判斷當前位置是否還符合其他條件,如果符合,就遍歷下一行(或列)所有位置,看看是否繼續有符合條件的位置,以此類推,如果某一個行(或列)的所有位置都不合適,就返回上一行(或列)繼續該行(或列)的其他位置遍歷,當我們順利遍歷到最後一行(或列),且有符合條件的位置時,就是一個可行的8皇后擺放方案,累加一次八皇后可行方案的個數,然後繼續遍歷該行其他位置是否有合適的,如果沒有,則返回上一行,遍歷該行其他位置,依此下去。這樣一個過程下來,我們就可以得出所有符合條件的8皇后擺放方案了。這是一個深度優先遍歷的過程,同時也是經典的遞歸思路。

     

      接下來,我們以逐列遍歷,具體到代碼,進一步說明。首先,從第一列開始找第一顆棋子的合適位置,我們知道,此時第一列的任何一個位置都是合適的,當棋子找到第一個合適的位置後,就開始到下一列考慮下一個合適的位置,此時,第二列的第一行及第二行顯然就不能放第二顆棋子了,因爲其與第一個棋子一個同在一行,一個同在一條斜線上。第二列第三行成爲第二列第一個合適的位置,以此類推,第三列的第5行又會是一個合適位置,這個過程中,我們注意到,每一列的合適位置都是受到前面幾列的位置所影響,歸納如下:

       

      假設前面1列的棋子放在第3行,那當前列不能放的位置就一定是3行,2行,4行。因爲如果放在這三行上就分別跟前一列的棋子同在一行、同在斜線、同在反斜線上,不符合我們的要求。現在我們用cols數組來表示8個列棋子所放的行數,數組下標從0開始,其中數組下標表示列數,數組的元素值表示該列棋子所在行數,當前列爲N(N>=0,N<8),即cols[N-1]=3,則有:

                          

                      cols[N] != cols[N-1](=3,表示不在同一行)

                     

                      cols[N] != cols[N-1]-1(=3-1=2,表示不在同一斜線上)

                     

                      cols[N]!=cols[N-1]+1(=3+1,表示不在同一反斜線上)

 

      這裏我們注意到,如果N-2列存在的話,那麼我們還要考慮當前列N不與N-2列的棋子同行,同斜線,同反斜線。把當前列N的前面的某一列設爲m,則m的所有取值爲{m>=0,m<N}的集合,故又可在上面式子的基礎,歸納爲如下:

                   

                    cols[N] != cols[m](與第m列的棋子不在同一行)

                   

                    cols[N] != cols­­[m] -(N-m)(>=0 ,與第m列的棋子不在同一斜線上)

                   

                    cols[N] != cols­­[m] + (N-m)  (<=8-1,與第m列的棋子不在同一反斜線上)          

 

           具體到代碼,很顯然,取m的所有值只需要一句循環,同時我們爲每一列定義一個長度爲8的布爾數組row[],下標同樣是從0開始,我們規定當row[i]=true時,表示該列第i行不能放棋子。這樣我們就能寫成下列程序段了:

         

       

                  

 

       好了,到此爲止,我們程序的核心內容都具備了,一個基於深度優先的遍歷流程和一個判斷位置是否合適的算法。下面貼出運行後算出的所有可行方案(即92種,“+”號代表空棋位,“0”代表皇后所在位置),源碼(注源碼變量名定義與上述略有不同,打印效果也不是圖片所顯示的效果,代碼有做些微改動)。

       打印結果

 

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