對抗搜索(二)

        在上一篇咱們分析了對抗搜索的基本思想,本文在上一篇的基礎上對算法部分步驟進行優化。首先咱們看一個基於對抗搜索創建的博弈樹,對上篇的內容作一個簡單的回顧。(本篇內容可使用上篇開頭說的兩本書做爲參考)java

        觀察這顆博弈樹,咱們可知它的固定深度是3,MAX先執行。換句話來講就是,MAX爲了決定第一步該走A、B仍是C,它要從根節點開始遍歷深度爲3的子樹。再換句話來講,這顆樹其實只是爲了得到MAX在第一步走的時候創建的博弈樹;一樣對於MIN方來講,假如MAX第一步選擇走A,那麼以A節點爲根節點,一樣創建一顆深度爲3的子樹,經過遍歷該子樹,得到MIN在這一步的最佳選擇,A一、A2或者A3(未畫出該圖)。算法

        通俗的說,對抗搜索其實就是在有限深度內枚舉雙發在每一步的選擇,經過比較最終節點的狀態(最大深度時)優劣,來得到此時執行方的最優選擇。函數

        迴歸到原圖,對MAX的選擇進行一個詳細的分析(請結合上一篇的MAX_VALUE和MIN_VALUE代碼):優化

  1.  第一步由MAX方執行,假設此時的節點狀態爲R,R有三個選擇,即三個後繼節點--A、B、C;R要在這三個選擇中選出「最利於獲勝」的節點做爲本身的執行步驟,按照極大極小值方法,即max(A,B,C),此時深度爲0;
  2. 接下來輪到MIN方執行,它要在R選擇的步驟基礎上,選擇利於本身的最優步驟,此時深度爲1;
  3. 接下來輪到MAX方執行,它一樣在MIN選擇的步驟基礎上,選擇利於本身的最優步驟,此時深度爲2;
  4. 接下來本應輪到MIN方執行,因爲它已經到達最大深度3,再也不往下「遞歸」,即到達了該樹的葉子節點,使用評價函數來計算當前葉子節點狀態的值。能夠看到每一個葉子節點都由一個評估值。
  5. 而後從葉子節點開始往上回溯,看到在深度2時,MAX方在每個選擇下的最優選擇;
  6. 繼續往上回溯,此時回溯到MIN方的選擇;
  7. 最終咱們回溯到最初MAX此時的最優選擇,選擇C做爲這一步的選擇;

        接下來咱們思考一個問題,咱們能夠看到上述的算法是對全部的候選項都進行枚舉遍歷比較,這樣若是深度比較大時,好比固定截取深度爲10,那麼對每一步來講都要計算最大深度爲10的子樹,這樣的計算量會很是大。有沒有可能縮小比較範圍?spa

        首先咱們要清楚,max_value和min_value方法以DFS(深度優先)進行遍歷。接下來咱們對以A節點爲根節點的子樹進行詳細分析。首先從深度3開始往上回溯時,此時A1的最優選擇爲6;此時再往上回溯,A節點此時的最優選擇爲6;而後開始遍歷A2節點,由於A節點此時的值是6,若是A2節點可以獲得該值的信息的話,那麼在以A2節點爲根的深度遍歷時,遇到比6大的值,其實能夠放棄該子樹的後續遍歷了。緣由就是A2節點是MAX方來執行,若是A2的子節點有比6大的,那麼MAX方確定會選擇比6大的值,而A節點是MIN方來執行,它要選擇的是A一、A二、A3的最小值,因此此時A節點確定不會選擇A2做爲最優選擇。code

        一樣,在A的選擇結束後,向上回溯到R,此時R的最優選擇是6,因爲R要選取最大值,那麼在對剩餘以B和C爲根節點進行深度遍歷時,若是有遇到比6小的值,那麼該節點確定不是最優的選擇。緣由就是MAX方要選擇後繼節點中的最大值,比6小的話,確定不是最優選擇。blog

        上述方法就是樹結構最經常使用的優化方法--剪枝,這裏的優化方法叫作Alpha-Beta方法。下面是經過Alpha-Beta剪枝方法對max_value方法和min_value方法的改進。遞歸

int max_value ( int dep , state s , int alpha , int beta ){
    if ( terminal ( s )) return e ( s ); //終止狀態
    if ( dep == maxdepth ) return e ( s ); //深度截斷,返回評價函數
    v = - inf ; //初始化爲負無窮
    succ = make_successors ( s ); // succ [ i爲第]個後繼狀態i
    for ( i = 0; i < succ . count ; i ++){
        v = max (v , min_value ( succ [ i ] , alpha , beta )); //計算全部兒子的最大值
        if ( v >= beta ) return v ; //β剪枝
        alpha = max ( alpha , v ); //更新α爲最大值
    }
    return v ;
}
int min_value ( int dep , state s, int alpha, int beta){
    if ( terminal ( s )) return e ( s ); //終止狀態
    if ( dep == maxdepth ) return e ( s ); //深度截斷,返回評價函數
    v = inf ; //初始化爲無窮大
    succ = make_successors ( s ); // succ [ i爲第]個後繼狀態i
    for ( i = 0; i < succ . count ; i ++){
    v = min (v , max_value ( succ [ i ] , alpha , beta )); //計算全部兒子的最小值
        if ( v <= alpha ) return v ; //α剪枝
        beta = min ( beta , v ); //更新β爲最小值
    }
    return v ;
}

         接下來咱們按照改進後的max_value方法和min_value方法對上述的博弈樹進行剪枝,方便你們理解。terminal

  1. 初始狀態,alpha=-inf, beta=inf (inf表明最大值);經過深度優先遍歷向下傳遞alpha, beta, 在到達葉子節點時,由於是計算評價函數alpha和beta其實沒有用;而後開始向上回溯到A1節點;
  2. A1節點回溯前alpha=-inf, beta=inf,回溯後變爲alpha=6, beta=inf;向上回溯到A節點;
  3. A節點回溯前alpha=-inf,beta=inf, 回溯後變爲alpha=-inf, beta=6; 向下遞歸遍歷A2節點;
  4. A2節點此時alpha=-inf, beta=6; 繼續向下遞歸遍歷,咱們知道A2是max方來執行,此時調用的是max_value方法,而且有三個後繼節點;
    1. 遍歷第一個節點時,2<6, alpha = 2, beta=6;
    2. 遍歷第二個節點時,8>6, 此時直接返回,也就是第三個節點再也不遍歷,由於max此時的選擇確定是大於6的,對A節點來講,A2節點確定不是最優的選擇;
    3. 此時向上回溯到A節點;
  5. 一樣對於A3節點來講,在遍歷完第一個節點7時,直接返回,繼續回溯到A節點;
  6. 此時A節點的alpha = -inf, beta=6; 此時A節點向上回溯到R節點;
  7. R節點回溯前alpha=-inf,beta=inf; 回溯後變爲alpha=6, beta=inf; R節點向下深度遍歷到B節點;
  8. B節點alpha=6, beta=inf; 繼續向下遞歸到B1節點;
  9. B1節點alpha=6, beta=inf; 繼續向下遞歸遍歷三個後繼節點,三個節點的值都比beta小,因此只是在每一個節點內部更改了alpha;最終回溯到B1節點;
  10. B1回溯前alpha=6, beta=inf, 回溯後alpha = 6, beta = inf; 接着向上回溯到B節點;
  11. B節點回溯前alpha=6, beta=inf, 此時回溯的值是5, 5<alpha=6, 直接回溯到R節點,也就是說直接裁剪了B2和B3節點值。緣由: 由於B節點是由MIN方來執行,它要選擇最小的節點做爲最佳選擇,因此不論B2和B3是什麼值,對於B來講最佳選擇確定是小於等於5;而R是選擇最大值,此時,R此時最優的選擇是6,確定不會選擇B節點做爲最優選擇,因此對於B2和B3來講,已經沒有繼續搜索的必要了;接着向上回溯到R節點;
  12. R節點回溯前alpha=6, beta=inf; 向下遞歸遍歷C節點;
  13. C節點alpha=6, beta=inf, 繼續向下遞歸遍歷C1;
  14. C1節點alpha=6, beta=inf, 繼續向下遞歸遍歷葉子節點, 因爲都小於beta, 因此依然只是比較alpha的值,獲取最大值向上回溯到C節點;
  15. C節點回溯前alpha=6,beta=inf, 回溯後alpha = 6, beta=7; 向下遞歸遍歷C2節點;
  16. C2節點alpha=6,beta=7, 向下遞歸遍歷葉子節點;
    1. 遍歷第一個葉子節點4, 小於beta;
    2. 遍歷第二個葉子節點8, 大於beta, 此時直接返回,裁剪了葉子節點1,直接向上回溯到節點C節點;
  17. C節點回溯前alpha = 6, beta=7;回溯後返回值爲8大於beta, 依然選取最小值,alpha=6, beta=7;
  18. 對於C3節點與C2的處理方式相同,C3向上回溯到C節點;
  19. C節點回溯前alpha=6,beta=7,回溯後alpha=6,beta=7, 並選擇最小值爲7回溯到R節點;
  20. R節點回溯前alpha=6,beta=inf,回溯後alpha=7,beta=inf;

    最終的裁剪圖以下,標紅的表明它的子樹都被裁剪了。class

總結

        alpha表明的是MAX方選擇的最小下界;

        beta表明的是MIN方選擇的最大上界;

相關文章
相關標籤/搜索