📌  相关文章
📜  博弈论中的极小极大算法第 4 组(Alpha-Beta 剪枝)

📅  最后修改于: 2021-09-24 03:18:34             🧑  作者: Mango

先决条件:博弈论中的极小极大算法,博弈论中的评估函数
Alpha-Beta 剪枝实际上并不是一种新算法,而是一种极小极大算法的优化技术。它大大减少了计算时间。这使我们能够更快地搜索,甚至可以进入博弈树的更深层次。它切断了游戏树中不需要搜索的分支,因为已经存在更好的移动可用。它被称为 Alpha-Beta 剪枝,因为它在 minimax函数传递了 2 个额外的参数,即 alpha 和 beta。
让我们定义参数 alpha 和 beta。
Alpha最大化器当前可以保证在该级别或更高级别的最佳值。
Beta最小化器当前可以保证在该级别或更高级别的最佳值。

伪代码:

function minimax(node, depth, isMaximizingPlayer, alpha, beta):

    if node is a leaf node :
        return value of the node
    
    if isMaximizingPlayer :
        bestVal = -INFINITY 
        for each child node :
            value = minimax(node, depth+1, false, alpha, beta)
            bestVal = max( bestVal, value) 
            alpha = max( alpha, bestVal)
            if beta <= alpha:
                break
        return bestVal

    else :
        bestVal = +INFINITY 
        for each child node :
            value = minimax(node, depth+1, true, alpha, beta)
            bestVal = min( bestVal, value) 
            beta = min( beta, bestVal)
            if beta <= alpha:
                break
        return bestVal
// Calling the function for the first time.
minimax(0, 0, true, -INFINITY, +INFINITY)

让我们通过一个例子来清楚地说明上述算法。

Alpha Beta 剪枝

  • 初始调用从A开始。此处 alpha 的值为-INFINITY ,而 beta 的值为+INFINITY 。这些值向下传递到树中的后续节点。在A 处,最大化器必须选择BC 的最大值,因此A首先调用B
  • B 处,最小化器必须选择DE 的最小值,因此首先调用D。
  • D 处,它查看其左子节点,即叶节点。此节点返回值 3。 现在D处的 alpha 值是 max( -INF, 3),即 3。
  • 为了决定是否值得查看其正确的节点,它会检查条件 beta<=alpha。这是错误的,因为 beta = +INF 和 alpha = 3。所以它继续搜索。
  • D现在查看它的右子节点,它返回值 5。在D 处,alpha = max(3, 5) 是 5。现在节点D的值是 5
  • D将值 5 返回给B 。在B 处,beta = min( +INF, 5) 即 5。现在保证最小值为 5 或更小。 B现在打电话给E看看他是否能得到一个低于 5 的值。
  • E处,alpha 和 beta 的值不是 -INF 和 +INF,而是分别是 -INF 和 5,因为 beta 的值在B 处发生了变化,这就是B传递给E 的值
  • 现在E查看它的左孩子,即 6。在E 处,alpha = max(-INF, 6) 是 6。这里条件成立。 beta 是 5,alpha 是 6。所以 beta<=alpha 是真的。因此它中断并且E将 6 返回给B
  • 请注意E的右孩子的值如何无关紧要。它可能是 +INF 或 -INF,它仍然无关紧要,我们甚至不必查看它,因为保证最小值为 5 或更小。因此,当最大化者看到 6 时,他知道最小化者永远不会以这种方式出现,因为他可以在B的左侧得到 5 。这样我们就不必查看那个 9,从而节省了计算时间。
  • E将值 6 返回给B 。在B 处,beta = min( 5, 6) 即 5。节点B 的值也是 5

到目前为止,这就是我们的博弈树的样子。 9 被划掉,因为它从未被计算过。

Alpha Beta 修剪 2

  • B将 5 返回给A 。在A 处, alpha = max( -INF, 5) 为 5。现在保证最大值为 5 或更大。 A现在调用C以查看它是否可以获得比 5 更高的值。
  • C 处,alpha = 5 且 beta = +INF。 C调用F
  • F 处,alpha = 5 且 beta = +INF。 F查看它的左孩子,它是 1。alpha = max( 5, 1) 仍然是 5。
  • F看它的右孩子是 2。因此这个节点的最佳值是 2。Alpha 仍然是 5
  • F将值 2 返回给C 。在C 处,beta = min( +INF, 2)。当 beta = 2 和 alpha = 5 时,条件 beta <= alpha 变为真。因此它中断了,它甚至不必计算G的整个子树。
  • 这种中断背后的直觉是,在C 处,保证最小值为 2 或更小。但是如果他选择B ,最大化者已经保证了 5 的值。那么为什么最大化器会选择C并得到小于 2 的值?您再次可以看到,最后两个值是什么并不重要。我们还通过跳过整个子树节省了大量计算。
  • C现在将值 2 返回给A 。因此, A处的最佳值是 max(5, 2),即 5。
  • 因此最大化器可以得到的最优值是 5

这就是我们最终的游戏树的样子。如您所见, G已被划掉,因为它从未被计算过。

Alpha Beta 修剪 3

CPP
// C++ program to demonstrate
// working of Alpha-Beta Pruning
#include
using namespace std;
 
// Initial values of
// Aplha and Beta
const int MAX = 1000;
const int MIN = -1000;
 
// Returns optimal value for
// current player(Initially called
// for root and maximizer)
int minimax(int depth, int nodeIndex,
            bool maximizingPlayer,
            int values[], int alpha,
            int beta)
{
     
    // Terminating condition. i.e
    // leaf node is reached
    if (depth == 3)
        return values[nodeIndex];
 
    if (maximizingPlayer)
    {
        int best = MIN;
 
        // Recur for left and
        // right children
        for (int i = 0; i < 2; i++)
        {
             
            int val = minimax(depth + 1, nodeIndex * 2 + i,
                              false, values, alpha, beta);
            best = max(best, val);
            alpha = max(alpha, best);
 
            // Alpha Beta Pruning
            if (beta <= alpha)
                break;
        }
        return best;
    }
    else
    {
        int best = MAX;
 
        // Recur for left and
        // right children
        for (int i = 0; i < 2; i++)
        {
            int val = minimax(depth + 1, nodeIndex * 2 + i,
                              true, values, alpha, beta);
            best = min(best, val);
            beta = min(beta, best);
 
            // Alpha Beta Pruning
            if (beta <= alpha)
                break;
        }
        return best;
    }
}
 
// Driver Code
int main()
{
    int values[8] = { 3, 5, 6, 9, 1, 2, 0, -1 };
    cout <<"The optimal value is : "<< minimax(0, 0, true, values, MIN, MAX);;
    return 0;
}


Java
// Java program to demonstrate
// working of Alpha-Beta Pruning
import java.io.*;
 
class GFG {
 
// Initial values of
// Aplha and Beta
static int MAX = 1000;
static int MIN = -1000;
 
// Returns optimal value for
// current player (Initially called
// for root and maximizer)
static int minimax(int depth, int nodeIndex,
                   Boolean maximizingPlayer,
                   int values[], int alpha,
                   int beta)
{
    // Terminating condition. i.e
    // leaf node is reached
    if (depth == 3)
        return values[nodeIndex];
 
    if (maximizingPlayer)
    {
        int best = MIN;
 
        // Recur for left and
        // right children
        for (int i = 0; i < 2; i++)
        {
            int val = minimax(depth + 1, nodeIndex * 2 + i,
                              false, values, alpha, beta);
            best = Math.max(best, val);
            alpha = Math.max(alpha, best);
 
            // Alpha Beta Pruning
            if (beta <= alpha)
                break;
        }
        return best;
    }
    else
    {
        int best = MAX;
 
        // Recur for left and
        // right children
        for (int i = 0; i < 2; i++)
        {
             
            int val = minimax(depth + 1, nodeIndex * 2 + i,
                              true, values, alpha, beta);
            best = Math.min(best, val);
            beta = Math.min(beta, best);
 
            // Alpha Beta Pruning
            if (beta <= alpha)
                break;
        }
        return best;
    }
}
 
    // Driver Code
    public static void main (String[] args)
    {
         
        int values[] = {3, 5, 6, 9, 1, 2, 0, -1};
        System.out.println("The optimal value is : " +
                            minimax(0, 0, true, values, MIN, MAX));
     
    }
}
 
// This code is contributed by vt_m.


Python3
# Python3 program to demonstrate
# working of Alpha-Beta Pruning
 
# Initial values of Aplha and Beta
MAX, MIN = 1000, -1000
 
# Returns optimal value for current player
#(Initially called for root and maximizer)
def minimax(depth, nodeIndex, maximizingPlayer,
            values, alpha, beta):
  
    # Terminating condition. i.e
    # leaf node is reached
    if depth == 3:
        return values[nodeIndex]
 
    if maximizingPlayer:
      
        best = MIN
 
        # Recur for left and right children
        for i in range(0, 2):
             
            val = minimax(depth + 1, nodeIndex * 2 + i,
                          False, values, alpha, beta)
            best = max(best, val)
            alpha = max(alpha, best)
 
            # Alpha Beta Pruning
            if beta <= alpha:
                break
          
        return best
      
    else:
        best = MAX
 
        # Recur for left and
        # right children
        for i in range(0, 2):
          
            val = minimax(depth + 1, nodeIndex * 2 + i,
                            True, values, alpha, beta)
            best = min(best, val)
            beta = min(beta, best)
 
            # Alpha Beta Pruning
            if beta <= alpha:
                break
          
        return best
      
# Driver Code
if __name__ == "__main__":
  
    values = [3, 5, 6, 9, 1, 2, 0, -1] 
    print("The optimal value is :", minimax(0, 0, True, values, MIN, MAX))
     
# This code is contributed by Rituraj Jain


C#
// C# program to demonstrate
// working of Alpha-Beta Pruning
using System;
     
class GFG
{
 
// Initial values of
// Aplha and Beta
static int MAX = 1000;
static int MIN = -1000;
 
// Returns optimal value for
// current player (Initially called
// for root and maximizer)
static int minimax(int depth, int nodeIndex,
                Boolean maximizingPlayer,
                int []values, int alpha,
                int beta)
{
    // Terminating condition. i.e
    // leaf node is reached
    if (depth == 3)
        return values[nodeIndex];
 
    if (maximizingPlayer)
    {
        int best = MIN;
 
        // Recur for left and
        // right children
        for (int i = 0; i < 2; i++)
        {
            int val = minimax(depth + 1, nodeIndex * 2 + i,
                            false, values, alpha, beta);
            best = Math.Max(best, val);
            alpha = Math.Max(alpha, best);
 
            // Alpha Beta Pruning
            if (beta <= alpha)
                break;
        }
        return best;
    }
    else
    {
        int best = MAX;
 
        // Recur for left and
        // right children
        for (int i = 0; i < 2; i++)
        {
             
            int val = minimax(depth + 1, nodeIndex * 2 + i,
                            true, values, alpha, beta);
            best = Math.Min(best, val);
            beta = Math.Min(beta, best);
 
            // Alpha Beta Pruning
            if (beta <= alpha)
                break;
        }
        return best;
    }
}
 
// Driver Code
public static void Main (String[] args)
{
     
    int []values = {3, 5, 6, 9, 1, 2, 0, -1};
    Console.WriteLine("The optimal value is : " +
                        minimax(0, 0, true, values, MIN, MAX));
 
}
}
 
// This code is contributed by 29AjayKumar


Javascript


输出 :

The optimal value is : 5

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程