【问题标题】:Is the tree data structure needed in the alpha-beta pruning algorithm?alpha-beta剪枝算法需要树数据结构吗?
【发布时间】:2023-09-28 13:26:01
【问题描述】:

alpha-beta剪枝算法如下:

function ALPHA-BETA-SEARCH(state) returns an action
      v <- MAX-VALUE(state, -∞, +∞)
      return the action in ACTIONS(state) with value v

function MAX-VALUE(state, α, β) returns a utility value
    if TERMINAL-TEST(state) then 
        return UTILITY(state)
    v <- -∞
    for each a in ACTIONS(state) do
        v <- MAX(v, MIN-VALUE(RESULT(state, a), α, β))
        if v ≥ β then
            return v
        α <- MAX(α, v)
    return v

function MIN-VALUE(state, α, β) returns a utility value
    if TERMINAL-TEST(state) then 
        return UTILITY(state)
    v <- +∞
    for each a in ACTIONS(state) do
        v <- MIN(v, MAX-VALUE(RESULT(state, a), α, β))
        if v ≤ α then 
            return v
        β <- MIN(β, v)
    return v

该算法指出ACTIONS 函数将给出给定state 中所有可用操作的列表。

让我们例如参加跳棋游戏。假设一个棋子,比如A,与另一个棋子成对角线,比如B。如果A 可以采取B,那么这是一个(不可避免的,因为如果可以的话,我们必须采取另一个检查器)行动。或者,如果有多个镜头,这些都是动作。这种情况实际上可以用铅笔和纸来绘制。更具体地说,可以使用树来表示这种情况,其中每个节点代表一个状态,其子节点的边代表该状态的可能动作。

我认为您不需要显式存储树数据结构。但是,上面的算法包含以下语句:return the action in ACTIONS(state) with value v。现在,ACTIONS(state) 将从某个状态返回可能的操作(例如,A 需要播放的位置)。

如果我们把所有的算法都算出来,我们会得到一个值v,我们会跟随从终端节点传递过来的值v的节点。

现在,假设我没有存储来自每个状态的所有可能移动或动作的完整树。当return the action ACTIONS(state) with the value v 被执行时,我只会得到引导我进入下一个状态的动作,并且我知道其中一个动作会引导我走向最佳路径。但是,如果我没有额外的簿记,例如完整的树,我能否将操作与值 v 匹配?

【问题讨论】:

    标签: algorithm artificial-intelligence minimax alpha-beta-pruning


    【解决方案1】:

    不应该在极大极小算法中构建显式树结构,而在实际情况下,您不能。具有深度界限 d 和分支因子 b 的极小极大算法遍历 O(dᵇ) 个节点大的树,很快得到太大而无法存储。 (在您发布的版本中,甚至没有深度限制,这意味着您将生成整个游戏树。)

    跟踪状态的方法是将顶层ALPHA-BETA-SEARCH重写为

    function ALPHA-BETA-SEARCH(state) returns an action
        best_a <- nil
        max_v <- -∞
        for each a in actions(state)
            v <- MIN-VALUE(RESULT(state, a), +∞, max_v)
            if v > max_v then
                max_v <- v
                best_a <- a
        return best_a
    

    也就是说,您在主函数中“展开”对MAX-VALUE 的顶部调用。

    请注意,在上面的函数中,您循环遍历每个动作 a,计算它们的 v。当某个v 是您迄今为止找到的最大值时,您知道您计算它的操作当前是best_a

    【讨论】:

    • 应该是 MIN-VALUE(RESULT(state, a), max_v, +∞) 而不是 MIN-VALUE(RESULT(state, a), +∞, max_v) ???跨度>
    【解决方案2】:

    我认为有两个问题需要回答您:

    1. 无论如何都会构建树 - 隐含地,每个 ACTIONS(vertex) op 可以简单地将 vertex 连接到他的每个儿子 - 所以无论如何都没有真正需要额外的树构建。而且,当然,您可以将v 等属性添加到该树的每个节点。

    2. 尽管如此,如果您不需要也不关心实际的树,一种可能的解决方案是返回 (v, state) [a tuple] 而不仅仅是 v。返回值的所有操作 - 将在 v 上完成,和现在一样,唯一真正使用 state 的人 - 是* ALPHA-BETA-SEARCH()。当然,它需要不太优雅的 MINMAX 函数,因为您不仅需要找到值 v,还需要找到给出该值的顶点。

    【讨论】: