1. 程式人生 > >「8-Queens Problem」皇后問題區域性極值啟發式搜尋方法

「8-Queens Problem」皇后問題區域性極值啟發式搜尋方法

8-Queens Problem皇后問題區域性極值啟發式搜尋方法

Backgrounds

背景說明:

皇后問題是演算法領域的著名問題,問題的背景是在8*8的國際象棋棋盤上擺滿8個皇后使之互相不能攻擊(由於皇后在國際象棋規則中橫、縱、斜三個方向均可以移動,即擺放要使得皇后兩兩不在同一橫、縱、斜線上)。放鬆這個問題的變長條件,我們可以將其擴大至N*N的棋盤上擺放N個皇后,使之各自在三個方向上不重複出現。

大一時剛剛學習程式語言的我們,在初次接到這道題時,主要是運用了遞迴函式和回溯的思想去解決問題,通過深度優先搜尋(depth-first search, DFS)策略,依次增加棋盤上可以擺放的位置。若遇到第k步棋子擺放的所有可能位置都發生衝突,則退回到第k-1步,修改k-1的狀態,以達到期望的最終解。

State space of 8-queens problem

皇后問題的狀態空間:

狀態空間,這裡理解成所有擺放的可能性情況。

皇后問題廣義的解的狀態空間,在沒有過多限制條件的情況下是非常龐大的。

在64個互不重複的位置上選擇無差別的8個位置,總計應該有C(64, 8)=4,426,165,368 (44億)大小的狀態空間. 圖示為較為集中的分佈情況和可以完全分散開的分佈情況。

  

        圖 1.1 皇后分佈緊湊          圖 1.2 皇后分佈鬆散 

注意這裡C(N*N, N)表示在N*N種方案中選擇N個的方案數

不同約束條件下的不同狀態空間規模:

實際上,全域性解狀態空間的大小也由我們的限制條件決定,下面提出兩種解決方案。但總體上策略一致地是,我們用一個長度為8的一維陣列表示每一列皇后的位置,這種表示方法首先就壓縮掉了很大一部分的解的狀態空間——因為相當於即使在橫向上有皇后可能會重合,這種每列一個位置數的表示方式放棄了同一列上出現多個皇后的情況。圖示為橫縱均不重合分散分佈和允許行重複的分佈情況。  

  

       圖 2.1 允許同行衝突 圖 2.2 保證橫縱均不衝突

但上述兩種表示方法出於求解出儘可能多的區域性極值和儘快求解出最優解的考慮,依然是穩妥的。此時狀態空間的大小至多已經被壓縮至8^8=16,777,216 (1670萬)種,相比於44億已經極大地壓縮瞭解的數量。

(1).第一種表示方法,我們在允許行重合的情況下,每次操作只在該列上對棋子進行上下移動,並考慮每次移動對於總衝突數的影響。

此種排列的狀態空間為8^8=16,777,216.

(2).第二種表示方法,我們對1~8的數字進行全排列,得到{a1, a2, …, ai, …, a8}用於表示第i 列上的皇后位置,這樣可以保證行列均不重複。

此種排列的狀態空間為8!=40,320. 

區域性極值和全域性最值的理解:

全域性最值,是對於每一個搜尋問題需要找到的最終結果。對於不同的問題,其問題的離散/連續性可能不同,解的數量、狀態分佈也不相同。皇后問題本身是一個離散問題(解的狀態空間數量是有限個數的,雖然解空間總規模可能非常大),且解的數量也是巨大的。至少對於8皇后,不存在唯一的狀態。後續執行程式可知,在不考慮翻轉、旋轉等價的情況下,有92組互不相同的解。即在橫縱均不重合的40,320規模的狀態空間(或在更大範圍的狀態空間中)有92組全域性最值。

區域性極值,是我們通過某種途徑趨向全域性最值時經過的、不能再用當前演算法得出相對更進一步的結果(而必須由重啟、重新打亂而繼續開始一次新的搜尋)時,“卡住”的狀態。


圖 3 搜尋路徑與全域性最優、區域性最優的關係

(state space為構成搜尋路徑的n維解空間的子集,objective function為目標函式)

對於同一個問題,我們考慮f(x1, x2, …, xi, …, xn)=K的目標函式,希望通過啟發式搜尋的方式尋找全域性K的最優值,即在n維解空間上,我們得到由目標函式f(.)決定的決策-目標曲面。在這個n+1維曲面S(X<x1, x2, …, xn>, K)上,不同的約束條件和演算法就相當於通過不同的n維路徑Ls<x1s, x2s, …, xns>去逼近全域性最優K.

其中Ls是某種啟發式搜尋演算法的搜尋路徑,對於特定的搜尋演算法,Ls是n維解狀態空間的有向路徑。記Ls上的每一步解為Xj, 並設該條路徑從某一初始狀態X0出發,經過p步可以到達全域性或區域性最優值(其中任意Xj都是n維狀態空間上的點),則該路徑Ls可以表示為Ls={X0, X1, …, Xj, …, Xp}. 由於狀態空間的不平整性,顯然通過不同的演算法定義到的區域性最優解(區域性極值)也是不同的。

注意這裡的定義包括後續目標函式的定義、估值函式的定義、最終的求解目的等等

Evaluation function

估值函式:

對於啟發式搜尋,我們需要在巨大的解的狀態空間中儘可能快地找出儘可能多的全域性最優解,這就需要我們在做每一步選擇(選擇繼續擴大解的已知範圍,使之儘快鋪展至n維或跳轉至下一個解的暫留狀態)時,能有效評判該解對於“發現最優解”這一目的的貢獻意義的函式。或者我們也可以這樣理解:搜尋演算法在在搜尋路徑的每一個解Xj停留時,並不知道該解是否處於到達全域性最優的必經路徑上,因此搜算演算法會根據一個估值函式,對“該步操作可以到達全域性最優或區域性最優”這一事件做出概率分析。當搜尋路徑Ls走到Xj-1這一步時,會對所有可能的後續狀態集合{Xj’|Xj’=Xj’1, Xj’2,…}進行估值,最後選出估值最大的一個Xj’作為Xj下一步。後續也據此方法繼續走下去。

當最終走到某一步,估值函式對所有可能的後繼都沒有最優估值或正向估值時,就說明搜尋路徑已經到達極值。此時檢查目標函式K即可判斷當前解是否是全域性最優。

需要說明的是,對於全域性最優,我們也可以有不同的定義方法。在本問題中,我們選擇用“衝突行、列或斜線上棋子數減一”表示衝突情況,即當某行、列或斜線上皇后棋子數目為0個或1個時,認為沒有衝突;皇后棋子數目為2個及以上時,認為衝突數是皇后數目-1. 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 int getChange(int i, int j) { int pi = position[i], pj = position[j]; // i-pi, j-pj // left: i+pi==j+pj, right: i-pi==j-pj // left[i+pi-1] left[j+pj-1] right[N-(i-pi)] right[N-(j-pj)] if (i+pi == j+pj) { // same left line return ((left[i+pi-1]>=3)+1) + (right[N-(i-pi)]>=2) + (right[N-(j-pj)]>=2) - ((right[N-(i-pj)]>=1)+1) - (left[i+pj-1]>=1) - (left[j+pi-1]>=1); else if (i-pi == j-pj) { // same right line return ((right[N-(i-pi)]>=3)+1) + (left[i+pi-1]>=2) + (left[j+pj-1]>=2) - ((left[i+pj-1]>=1)+1) - (right[N-(i-pj)]>=1) - (right[N-(j-pi)]>=1); else { // (i, j) no collision return (left[i+pi-1]>=2) + (left[j+pj-1]>=2) + (right[N-(i-pi)]>=2) + (right[N-(j-pj)]>=2) - (left[i+pj-1]>=1) - (left[j+pi-1]>=1) - (right[N-(i-pj)]>=1) - (right[N-(j-pi)]>=1); } }

圖 4 估值函式

當發現兩列(i, j) 可以被操作時,我們通過計算“交換後”與“交換前”兩種狀態(兩個不同的解的停留點)之間目標函式即總衝突數的變化量,判斷該步操作是否應被執行。其中我們考慮了交換前的(i, j)兩列處於左斜向衝突(交換後存在右斜向衝突)、右斜向衝突(交換後存在左斜向衝突)、無衝突(交換後彼此依然無衝突)三種情況。 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void statistic() { clear(); for (int i=1; i<=N; ++i) { int pi=position[i]; left[i+pi-1]++; right[N-(i-pi)]++; } } void reCount() { statistic(); Collision = 0; leftCollision = 0, rightCollision = 0; for (int i=1; i<=2*N-1; ++i) { if (left[i]>=2) leftCollision += left[i]-1; if (right[i]>=2) rightCollision += right[i]-1; } Collision = leftCollision + rightCollision; }

圖 5 目標函式定義,顯然Collision=0時取得全域性最優解

Main Algorithm

狀態空間壓縮:

我們選擇交換不重複的列來完成全域性最優的搜尋結果,這樣可以在本身就比較小的狀態空間(40,320種)範圍內得出結果。並且對於全域性最優來說,由於所有的全域性最優解均包含在該狀態空間中,全域性最優的分佈率也最高。

重啟策略:

初始化時生成1到8的升序列並進行時間複雜度O(n)的遍歷,每次隨機出一個位置,將其與當前掃到的位置做一次交換。之後每次重啟僅對現有列進行一次隨機交換即可得到一個新的解空間上的X0作為新的一條搜尋路徑Ls的起點。

搜尋策略: 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public: void solve(bool ptl) { bool moveOn = true; int EFT = 0; rebootCount = 0; reCount(); // initialization process startCTime = clock(); while (!finish()) { // Terminate reboot(); rebootCount++; reCount(); EFT=0; moveOn=true; while (moveOn) { moveOn = false; for (int i=1; i<=N; ++i) { for (int j=1; j<i; ++j) { // -------------beginforeach i, j EFT = 0; // for any 'i' col & 'j' col if (collapsed(i, j)) { // (i, j) pair collapsed EFT = getChange(i, j); else EFT = -1; if (EFT>0) { // still trends to minimal moveOn = true; // do position swapping // maintain the array 'left' & 'right' execSwap(i, j); } reCount(); // -------------------------- endforeach i, j } } } if (ptl) { puff(); prinf(); } } endCTime = clock(); costCTime = endCTime - startCTime; }

圖 6 主要搜尋方法

用兩個主要變數控制搜尋程序:

int EFT用來衡量每次可交換列的對(i, j)交換後的估值函式值;

bool moveOn判斷當前迴圈是否有效,即是否有正向估值產生。

每當一步搜尋不能產生正向估值,即無論如何移動也不能使總的衝突數減小時,一個新的區域性極值就可能被找到了。這時我們若判斷出總衝突數降至0則可以進一步說明這個極值也是一個全域性最優。

Local search strategy

貪心與模擬退火:

爬山問題中,我們判斷當前搜尋方向是否還會繼續趨向於更大值。若當前搜尋方向上不再出現上升態勢,搜尋會停止並駐留在當前解上(即區域性最優解),所以爬山策略是一種嚴格貪心演算法,不保證可以找到全域性最優。

模擬退火演算法正是通過增加一定機率的反向跳轉趨勢,使得搜尋位置得以“逃脫”區域性最優,獲得移動到全域性最優的可能;通過控制反向跳轉機率的收斂,使得解有更大可能性最終停留在全域性最優解上。

區域性搜尋策略:

皇后問題中,區域性最優解的分佈較為稠密,全域性最優解的比例也相對較高。這使得模擬退火等一般意義上的概率收斂不一定能取得較好的效果。

Simple Statistic

簡單統計結果:

下面給一個執行的例子 

50000次執行求出最優解,平均每個最優解的求得只需要2.6次重啟,即經過2.6個區域性最優解到達了全域性最優;啟動最多的也只有25次;平均耗時極短。  


程式打印出的一些區域性極值示意圖微笑

ps. 最近新開通了部落格 會放一些學習過程中的心得體會(和一些作業或者報告)

如果你覺得有用,歡迎分享,謝謝!

相關推薦

8-Queens Problem皇后問題區域性極值啟發式搜尋方法

「8-Queens Problem」皇后問題區域性極值啟發式搜尋方法 Backgrounds 背景說明: 皇后問題是演算法領域的著名問題,問題的背景是在8*8的國際象棋棋盤上擺滿8個皇后使之互相不能攻擊(由於皇后在國際象棋規則中橫、縱、斜三個方向均可以移動,即擺放要使得皇

8條件語句

tin str 條件表達式 邏輯 屬於 static 鍵盤錄入 sca logs 1、簡單if語句   ●語法     if、else屬於條件分支語句          if (條件) {        ←條件表達式或邏輯表達式       //語句1       ←條件成

mysql優化專題視圖應用竟然還可以這麽優化?不得不收藏(8

tables 特殊 (六) 語句 混合 存儲 lte 一對一 註意力 一、視圖概述(技術文): (1)什麽是視圖? 視圖是基於 SQL 語句的結果集的可視化的表。 視圖包含行和列,就像一個真實的表。視圖中的字段就是來自一個或多個數據庫中的真實的表中的字段。視圖並不在數據庫中

8天14時換算成具體的小時數,Python輕鬆搞定

資料準備 背景需要將【8天14時】換算成具體的 小時數, 為下一步的資料預測模型 做資料準備, 資料預處理資料如下: 更多Python視訊、原始碼、資料加群960410445免費獲取 引子 正常的計算兩個日期小時差的程式碼如下:  

8 Queens Chess Problem

題目:八皇后模型,輸出包含了某一點的所有皇后 注意:格式上,不同輸入之間空兩行。數字的最後沒有空格,所以把空格寫在前面。還有最後一行輸出後,後面沒有空行了 #include <cstdio&g

zoj 2778 - Triangular N-Queens Problem

tracking set 成功 皇後 ont pri problem 分析 angular 題目:在三角形的棋盤上放n皇後問題。 分析:找規律題目。依照題目的輸出,能夠看出構造法則; 先填奇數,後填偶數。以下我們僅僅要證明這樣的構造的存在性就可以

loj516 LibreOJ β Round #2DP 一般看規律

clear pac ret stdio.h eoj 技術 sort logs targe 傳送門:https://loj.ac/problem/516 【題解】 那段代碼求的是相同的數中間隔最小的值。 離散後用set維護每個值出現次數,每次操作相當於合並兩個set,這步可以

cogs2652 秘術天文密葬法

splay 題目 bit 復雜 one 廣告 turn lap 等於 傳送門:http://cogs.pro/cogs/problem/problem.php?pid=2652 【題解】 學習了一發長鏈剖分,感覺十分茲磁 廣告:長鏈剖分 - fjzzq2002 那麽我再說一

Nescafé26 Freda的傳呼機 【最短路徑+書上倍增】

試驗 一位 bre 最短路 isp add 交流 實現 continue 題目: 為了隨時與rainbow快速交流,Freda制造了兩部傳呼機。Freda和rainbow所在的地方有N座房屋、M條雙向光纜。每條光纜連接兩座房屋,傳呼機發出的信號只能沿著光纜傳遞,並且傳呼機的

Nescafé26 Freda的傳呼機 【樹上倍增+圖論】

|| color div swa amp ons col 最短距離 r+ 題目: 為了隨時與rainbow快速交流,Freda制造了兩部傳呼機。Freda和rainbow所在的地方有N座房屋、M條雙向光纜。每條光纜連接兩座房屋,傳呼機發出的信號只能沿著光纜傳遞,並且傳呼機的

LibreOJ #514. LibreOJ β Round #2模擬只會猜題意

clas oid loj gist mem bsp num clu n) 二次聯通門 : LibreOJ #514. 「LibreOJ β Round #2」模擬只會猜題意 /* LibreOJ #514. 「LibreOJ β Round #2

一元治愈微信應用的臉盲癥

解決 帳號 mongodb 裏的 cin 檢測 公司 使用場景 替代 「臉盲癥」是一種經過正式確認的疾病,全名「面部辨識能力缺乏癥」。古裝劇裏的姑娘戴上面紗少俠就認不出了?下次遇到這種情節別吐槽編劇啦,興許這位少俠就患有臉盲癥呢。 其實在很多方面,計算機軟件不止一次吊打了

LibreOJ #525. LibreOJ β Round #4多項式

cnblogs for getchar 多項式 tps cst row style clu 二次聯通門 : LibreOJ #525. 「LibreOJ β Round #4」多項式 官方題解 : /* LibreOJ

LibreOJ #515. LibreOJ β Round #2貪心只能過樣例

tdi thml http column printf name target sum pro 題目描述 一共有 nnn個數,第 iii 個數 xix_ix?i?? 可以取 [ai,bi][a_i , b_i][a?i??,b?i??] 中任意值。設

mysql優化專題90%程序員面試都用得上的索引優化手冊(5)

根據 eat index 重要 進行 需要 範圍查詢 記錄 文件的 目錄(技術文) 多關於索引,分為以下幾點來講解: 一、索引的概述(什麽是索引,索引的優缺點) 二、索引的基本使用(創建索引) 三、索引的基本原理(面試重點) 四、索引的數據結構(B樹,hash) 五、創建索

mysql優化專題這大概是一篇最好的mysql優化入門文章(1)

left 機械 增刪改查 靜態 命中 mysql查詢 關註 mysq 增刪改 優化,一直是面試最常問的一個問題。因為從優化的角度,優化的思路,完全可以看出一個人的技術積累。那麽,關於系統優化,假設這麽個場景,用戶反映系統太卡(其實就是高並發),那麽我們怎麽優化? 如果請

mysql優化專題單表查詢優化的一些小總結,非索引設計(3)

flush src innodb atp show 優化 ase 驗證 where子句 單表查詢優化:(關於索引,後面再開單章講解) (0)可以先使用 EXPLAIN 關鍵字可以讓你知道MySQL是如何處理你的SQL語句的。這可以幫我們分析是查詢語句或是表結構的性能瓶頸。

mysql優化專題你們要的多表查詢優化來啦!請查收(4)

ref 分享 標準 select查詢 多表 連接 sts mysq 子查詢 一、多表查詢連接的選擇: 相信這內連接,左連接什麽的大家都比較熟悉了,當然還有左外連接什麽的,基本用不上我就不貼出來了。這圖只是讓大家回憶一下,各種連接查詢。 然後要告訴大家的是,需要根據查詢的情

mysql優化專題什麽是慢查詢?如何通過慢查詢日誌優化?(10)

logs stat bst 二進制日誌 help use dumps 根據 客戶 日誌就跟人們寫的日記一樣,記錄著過往的事情。但是人的日記是主觀的(記自己想記的內容),而數據庫的日誌是客觀的,根據記錄內容分為以下好幾種日誌(技術文): a、錯誤日誌:記錄啟動、運行或停止my

mysql優化專題詳解引擎(InnoDB,MyISAM)的內存優化攻略?(9)

區域 order by 順序 重做日誌 浪費 變量 效率 攻略 分區 註意:以下都是在MySQL目錄下的my.ini文件中改寫(技術文)。 一、InnoDB內存優化 InnoDB用一塊內存區域做I/O緩存池,該緩存池不僅用來緩存InnoDB的索引塊,而且也用來緩存InnoD