日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

Alpha-Beta剪枝的原理的深入理解(无图预警)

發布時間:2023/12/29 windows 40 coder
生活随笔 收集整理的這篇文章主要介紹了 Alpha-Beta剪枝的原理的深入理解(无图预警) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載請注明 原文鏈接 :https://www.cnblogs.com/Multya/p/17929261.html

考慮一個樹:

一棵樹上只有葉子節點有值,有確定的根節點的位置

根據層數來劃分葉子節點和根節點之間的鏈接節點

偶數層上的值取子節點的最大值,奇數取最小

因為葉子節點上的值確定,在有這么個規則之后整棵樹上所有節點就定下來了吧

現在我遮住全部葉子節點,讓你通過打開盡量少次數葉子節點,確定根節點的值

我們通過alpha-beta 剪枝來實現

確定的事情:

  • 一個節點上的值必定是長在它身上的所有葉子的值中的一個
  • max{ a, min{b,x} } 如果b比a小,無論x取什么,結果都是a
  • min{ a, max{b,x} } 如果b比a大,無論x取什么,結果都是a

為什么? 我們放慢這個思考過程看看背后的邏輯

我們用一個區間來表示這個算式最后的結果的范圍,下界是a,上界是b

我們知道計算最大最小的過程,其實就是一個單邊的區間不斷根據新的值刷新的過程:

假設計算max{4,5,1}

第一個數是4暫定是表達式的值

然后4確定下界是4的區間,這個區間希望得到一個在這個區間內的數刷新區間下界和更新表達式的值。5在這個區間內,所以它能刷新表達式和更新區間下界

1不在這個區間內,所以它不能更新表達式和區間。所以表達式是最后更新狀態下的5,計算正確

刷新區間的操作也可以用求交集來實現,這樣的話就省了判斷的那一步,然后結果也可以用最后的下界來確定

所以可以變成這樣:

求區間(4,+ \(\infty\) )∩(5,+ \(\infty\) )∩(1,+ \(\infty\) )的下界

這樣我們就實現了用區間來求最大(最小)的功能

再看max{ 4, min{3,1} }

第一個數是4暫定是表達式的值

然后4確定下界是4的區間,這個區間希望得到一個在這個區間內的數刷新區間下界和更新表達式的值

這個區間希望表達式min{3,1}得到一個大于4的數刷新區間下界和更新表達式的值(這個過程區間原封不動傳遞下去)

先計算表達式min{3,1} 第一個數是3,然后5確定表達式在小于3的區間內,希望得到一個小于5的值刷新表達式

但是這個區間內所有的數都不在上個表達式期望的大于4的數區間內(區間不重合),也就是這個表達式所有可能的值都不能刷新上個表達式的值,所以跳過計算這個子表達式

由于上個表達式所有數遍歷完了,最后更新的數是4,所以表達式值為4

我們再來看完全用區間來實現的方法:(【】內計算得到一個數)所有都是閉區間哈,意會就行

求(4,+ \(\infty\) )∩ ( min{3,1} ,+ \(\infty\) )的下界

即求(4,+ \(\infty\) )∩ (【(- \(\infty\) ,3)∩ (- \(\infty\) ,1)的上界】,+ \(\infty\) )的下界

我們定義空區間的上界是正無窮,下界是負無窮,這樣做的理由是使空區間對結果不產生任何貢獻(因為都是取交集)

然后是關鍵的一步:根據上面的啟發,我們把前面得到的區間套一層殼,也就是:

等價為求(4,+ \(\infty\) )∩ (【(4,+ \(\infty\) )∩【(- \(\infty\) ,3)∩ (- \(\infty\) ,1)的上界】的上界】,+ \(\infty\) )的下界

這個結果不變。因為【(4,+ \(\infty\) )∩【(- \(\infty\) ,3)∩ (- \(\infty\) ,1)的上界】的上界】的結果不是空集的話對上界沒有影響,是空集的話沒有貢獻。

可以等價為(4,+ \(\infty\) )∩ (【(4,+ \(\infty\) )∩(- \(\infty\) ,3)∩ (- \(\infty\) ,1)的上界】,+ \(\infty\) )的下界,因為取交集,先后沒有影響。

此時可以先通過判斷(4,+ \(\infty\) )∩(- \(\infty\) ,3)是空集來提前結束求值,得到最后區間(4,+ \(\infty\)

像上面這樣,如果把傳遞給子表達式期望的區間和子表達式結果的區間看成一回事的話,那就是alpha-beta剪枝的邏輯。回到最開始的那個樹。這個區間能被固定在每一個節點身上,表示這個節點的狀態如果要刷新這個節點的值,要求新輸入的值的區間范圍。如果這個節點從未被刷新,那么這個節點的值就不會產生任何貢獻來刷新上一個表達式的值。如果這個區間是一個空區間,那么所有的值都不能刷新這個節點的值,那么就沒有必要繼續給這個節點輸入值了。

觀察區間動向的話會發現有關區間的操作有以下幾種:

  • 把值改寫為區間
  • 區間取交集
  • 取區間一端的數傳遞回去
  • 把一個區間傳遞給子表達式內提前取交集

再看max{ 4, min{3,1} },這次我們加上樹的形狀和葉子節點遮擋的特性

自行畫圖:有4 3 1三個節點,一個根節點,兩個鏈接節點,三個葉子節點

開始。打開葉子4,更新所連接的父節點

這里將每個節點區間初始化為全體實數,因為是MAX層,刷新這個節點的區間為(4,+ \(\infty\)

傳遞(4,+ \(\infty\) )給鏈接3和1的鏈接節點(此時我們還不知道3和1)

鏈接節點打開葉子3,因為是MAX層,產生區間(- \(\infty\) ,3)

原來已經有集合了,取交集為空集,提前結束運算,不做任何貢獻,不傳遞值回去

這樣就完成了任務,只打開了4和3就知道了根節點的值是4

如果把前面的值用負號在min層取反,那么所有的層的操作邏輯都變成一樣的了

alpha-beta剪枝的算法的代碼:

//意義:目前棋盤的最值評分 分數的正負取決于一開始的isBlackNow
int abSearch(int floor, int alpha, int beta, bool isBlackNow, Coord &searchResult) {
    int tmpScore, moveCount = 0;
    Coord tempSearchResult{};
    //優化1
    std::vector<ScoreCoord> possibleMove = generatePossibleMove(isBlackNow);
    for (auto &now: possibleMove) {
		//優化2
        moveCount++;
        if (moveCount > 8) break; //只搜索前8個可能的落子點
        int x = now.coord.x, y = now.coord.y;
        m_map[x][y] = isBlackNow ? BLACK_CHESS : WHITE_CHESS;
        //優化3
        if (someoneWin({x, y})) {//如果有人贏了 必定是下這個子的人贏了
            searchResult = {x, y};
            tmpScore = evaluateAll(isBlackNow);//返回這個局面最高的得分,也就是贏局的分數
            m_map[x][y] = NO_CHESS;
            return tmpScore;
        }
        //單層搜索
        if (floor == 1) {//如果只看這一步子 那就是這一步子所有可能的得分中的最大值
            tmpScore = evaluateAll(isBlackNow);
            m_map[x][y] = NO_CHESS;
            if (tmpScore > alpha) {
                alpha = tmpScore;
                searchResult = {x, y};
            }
            continue;
        }
        tmpScore = -abSearch(floor - 1, -beta, -alpha, !isBlackNow, tempSearchResult);//不然得分就是我下了之后的對方的所能得到的最高分取負
        m_map[x][y] = NO_CHESS;
        if (tmpScore >= beta) {
            return beta;
        }
        if (tmpScore > alpha) {//取對方盡所有努力后得到最大值中的最小的一個 取負值后變成最大的一個
            alpha = tmpScore;
            searchResult = {x, y};
        }
    }
    return alpha;
}

抽象出來的偽代碼:

//意義:目前棋盤的最值評分 分數的正負取決于一開始的isBlackNow
int abSearch(int floor, int alpha, int beta, bool isBlackNow, Coord &searchResult) {
    possibleMove = generatePossibleMove();
    for (auto &now: possibleMove) {
	    downOneStep();
        if (someoneWin()) {//如果有人贏了 必定是下這個子的人贏了
            saveSearchResult();
            restoreLastStep();
            return evaluateScore();
        }
        //單層搜索
        if (floor == 1) {//如果只看這一步子 那就是這一步子所有可能的得分中的最大值
            tmpScore = evaluateScore();
            restoreLastStep();
            if (tmpScore > alpha) {
                alpha = tmpScore;
                saveSearchResult();
            }
            continue;
        }
        tmpScore = -abSearch(floor - 1, -beta, -alpha, !isBlackNow, tempSearchResult);//不然得分就是我下了之后的對方的所能得到的最高分取負
        restoreLastStep();
        if (tmpScore >= beta) {
            return beta;
        }
        if (tmpScore > alpha) {//取對方盡所有努力后得到最大值中的最小的一個 取負值后變成最大的一個
            alpha = tmpScore;
            saveSearchResult();
        }
    }
    return alpha;
}

總結

以上是生活随笔為你收集整理的Alpha-Beta剪枝的原理的深入理解(无图预警)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。