人工智能初步——利用隨機重啟爬山、模擬退火算法求解2n皇后問題

這兩天在寫AI的課程實驗,趁剛剛完結實驗代碼,腦海中還有些思路,在此簡單總結一下。

目錄

問題描述

2N皇后問題:給定一個n*n的棋盤。現要向棋盤中放入n個黑皇后和n個白皇后,使任意的兩個黑皇后都不在同一行、同一列或同一條對角線上,任意的兩個白皇后都不在同一行、同一列或同一條對角線上。請盡量快地給出一組可行解。

關于N皇后問題

N皇后問題是一個很經典的問題,在大家最初學習算法的時候都有討論過。回溯法是經典的解法,但是隨著N的增大,其復雜度的增加呈指數增長。哪怕N只是為100,使用回溯解法的話,運行也要相當久的時間。

簡單分析

對于2N皇后問題,很多同學的第一想法可能是兩次求解N皇后問題,且第二次求解時為擺放位置設限。然而,這種做法不免顯得過于繁瑣。

我們在這里,不妨先簡單地分析了一下幾種情況:

1. 當N為偶數時:其實只要求得一組可行解即可,另外一組可行解可以由當前解沿N*N矩陣的中軸線作對稱變換得到。因為N為偶數,所以不會存在黑白皇后位置沖突的情況。
  例如:N=4時,求得一組可行解為:3 1 4 2,按著這個思路,變換得到另一組可行解為:2 4 1 3。可以判斷,這樣的兩組解合并起來是符合題目要求的。

2. 當N為奇數時:沿中軸線對稱的方式不再可行,因為肯定有一個皇后會落在中軸線上。此時,可以考慮通過中心點作點對稱的情況。
  這里要注意,如果求得的可行解存在關于中心點對稱的皇后擺放(或有皇后位于中心點),那么此解不合要求,需要重新再求;直到沒有兩個皇后的位置是關于中心點對稱的,另一組解可以通過對當前解關于中心點作點對稱變換得到。
  例如,N=5時,求得一組可行解為:2 4 1 3 5,按著這個思路,變換得到另一組可行解為:1 3 5 2 4。可以判斷,這樣的兩組解合并起來是符合題目要求的。

從上可以看出,其實2N皇后問題并不需要二次求解N皇后,在大多數情況下只需求得一組可行解即可。

爬山算法

在介紹爬山算法之前,我覺得很有必要先弄清楚什么是局部搜索。

局部搜索

從數學層面來理解,局部搜索是一種解決最優化問題的啟發式算法。

對于某些計算起來非常復雜的最優化問題,比如各種 NP 完全問題,要找到最優解所需要的時間會隨問題規模的增大呈指數增長,因此誕生了各種啟發式算法來退而求次地尋找局部最優解,而局部搜索算法就是其中的一種算法。

局部搜索算法從某一狀態(而不是多條路徑)出發,通常只移動到與當前狀態相鄰的狀態。而在典型情況下,搜索的路徑是不保留的。盡管局部搜索算法不是系統化的求解方法,但是它有幾個關鍵的優點:

1. 占用很少的內存,通常情況下容量是常數級別的。
2. 經常能在不適合系統化算法的很大或者無限的(連續的)狀態空間中快速找出合理的解。

爬山算法簡介

爬山算法屬于局部搜索算法的一份子,因此是一種解決最優化問題的啟發式算法。

在實際運用中,爬山算法不會前瞻與當前狀態不直接相鄰的狀態,只會選擇比當前狀態價值更好的相鄰狀態,所以簡單來說,爬山算法是向價值增長方向持續移動的循環過程。

由于它的貪婪特性,使得在解決問題中容易陷入局部極大值(Local maxima,指一個比所有鄰居狀態價值要高但是比全局最大值要低的狀態),我們能采取隨機重啟(Random restart)以及模擬退火(Simulated annealing)的方法來改進。本文的主要涉及的就是這兩種算法。

先在這里簡單地說一下它們之間的區別,主要在于如何選擇下一狀態以及如何有效地得到全局最優解:

1. 隨機重啟爬山算法:  
   求解過程中,當得到了局部極大值時,如果不是全局最優解,則隨機生成初始狀態,重新求解,直到得到全局最優解。  
2. 模擬退火爬山算法:
   基于隨機爬山算法,允許在隨機選擇相鄰狀態的時候有概率地選擇價值更小的狀態。在初期,向低價值狀態移動的概率高,隨著時間流逝該概率會越來越低。(溫度逐漸降低,即"退火"。)

算法實現與關鍵優化

初始化

不同于一般的隨機初始化。我實現時采用的初始化方式為:先依次為每一行的對應列擺上皇后,如第i 行,那么皇后就擺在第i 列,之后再隨機選擇交換皇后所在列。

這樣做的優點是可以保證在任一時刻,每一行每一列都只有一個皇后,大大縮小了搜索范圍,節省了程序運行時間。(從我的程序運行耗時可以明顯看出這一策略的優越性。)

具體的實驗代碼如下:

/*初始化函數:在每行每列放置一個皇后*/
void generate_status(int* status) {
    for (int i = 0; i < N; i++) {
        status[i] = i;
    }
    /*隨機交換*/
    srand((unsigned)time(NULL));
    for (int i = 0; i < N; i++) {
        int r = rand();
        r = r % N;
        swap(status[r], status[N - r - 1]);
    }
}

評價函數

對于每一個狀態,需要有一個評價函數對其進行估值評價。在此,我選用沖突數作為評價指標,存在沖突數越多的狀態,其評價就越差。顯然,最優解的評價結果為0,即不存在沖突。

為了進一步優化實驗運行效果,此函數我設置為內聯函數。

具體的實驗代碼如下:

/*評價函數:返回擺放狀態的沖突數*/
inline int evaluate(int* status, CollisionList& collision_list) {
    collision_list.clear();
    int num = 0;
    for (int i = 0; i < N; i++) {
        for (int j = i+1; j < N; j++) {
            int offset = j - i;
            if (abs(status[i] - status[j]) == offset) {
                collision_list.push_back(j);
                num += 1;
            }
        }
    }
    return num;
}

嘗試交換函數

對傳入的狀態進行交換嘗試,如果交換后的狀態評價結果小于當前傳入狀態,就進行交換,將新狀態返回;否則,不交換,直接返回原先的狀態。
  對于模擬退火算法,這里就需要加上一個temperature變量,當鄰居狀態不是更優,但是溫度夠高,達到了振蕩指標時,也可以進行狀態轉換。同時,temperature值是在不斷減小的。

尋找下一個更優狀態的函數

對于傳入的狀態,不斷調用嘗試交換函數,直到獲得了沖突數更小的新狀態,即為一個更優狀態,將此狀態的沖突數作為返回值返回。

N皇后解法的主函數

這個函數的主要實現的就是調用初始化函數進行初始化,然后持續迭代調用尋找下一個更優狀態函數,直到返回的沖突數指標為0時,可以將此狀態作為求得的一組可行解再交還給main函數。

算法效率比較

下面就是見證奇跡的時刻啦~~~
  筆者特意寫了一份回溯法求解N皇后問題的程序,作為對比參照。

N=10時:


回溯法求解10皇后問題
爬山算法求解10皇后問題

額,好像N設的有點小了。。。。來個大點的。。。。

N=20吧:


爬山算法求解20皇后問題

  什么?回溯法?這。尷尬了。。等了好久都沒跑出來結果。。。
  退而求其次,我跑了個N=16的回溯法給大家瞧瞧,不過也是讓我足足等了5分多鐘:


回溯法求解16皇后問題

可見當N>10以后,爬山算法的優越性盡顯無疑,我于是又給它上了幾個更大的數,具體的運行效果如下:


爬山算法求解100皇后問題
爬山算法求解300皇后問題
爬山算法求解1000皇后問題

爬山算法 N=1000的耗時也不過是回溯法 N=16情況運行耗時的一半!
  AI的強大之處可以略窺一二了吧~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內容