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

📅  最后修改于: 2021-04-29 01:53:15             🧑  作者: Mango

先决条件:博弈论中的极小极大算法,博弈论中的评估函数

Alpha-Beta修剪实际上并不是一种新算法,而是针对minimax算法的一种优化技术。它极大地减少了计算时间。这使我们可以更快地进行搜索,甚至可以进入游戏树的更深层次。它切断了游戏树中不需要搜索的分支,因为已经存在一个更好的移动方法。之所以称为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
  • DB返回值5。在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并因此节省了计算时间。
  • EB返回值6。在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
  • FC返回2的值。在C处,β= min(+ INF,2)。当beta = 2且alpha = 5时,条件beta <= alpha变为真。因此它会中断,甚至不必计算G的整个子树。
  • 这种突破的直觉是,在C处,最小化器的值保证为2或更小。但是,如果他选择B,则已经保证了最大化器的值为5。那么,为什么最大化器会选择C并得到小于2的值?再次您可以看到,最后两个值是什么并不重要。通过跳过整个子树,我们还节省了大量计算。
  • C现在向A返回2的值。因此, A处的最佳值为max(5,2),即5。
  • 因此,最大化器可以获得的最佳值为5

这就是我们最终的游戏树的样子。如您所见,因为从未计算过G ,所以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


输出 :

The optimal value is : 5