Minimax 是一种回溯算法,用于决策制定和博弈论,以在假设您的对手也以最佳方式下棋的情况下为玩家找到最佳走法。广泛应用于二人回合制游戏,如井字游戏、西洋双陆棋、棋盘棋、国际象棋等。
在 Minimax 中,这两个玩家被称为最大化者和最小化者。最大化器试图获得尽可能高的分数,而最小化器则试图做相反的事情并获得尽可能低的分数。
每个董事会状态都有一个与之相关的值。在给定状态下,如果最大化者占上风,则棋盘的分数将趋于某个正值。如果最小化者在该棋盘状态中占上风,那么它往往会是一些负值。棋盘的值是通过一些启发式计算的,对于每种类型的游戏都是独一无二的。
例子:
考虑一个游戏,它有 4 个最终状态,到达最终状态的路径是从根到 4 个完美二叉树的叶子,如下所示。假设您是最大化玩家并且您有第一次移动的机会,即您在根部而您的对手在下一个级别。考虑到你的对手也打得最好,你作为一个最大化玩家会采取什么行动?
由于这是一种基于回溯的算法,它会尝试所有可能的移动,然后回溯并做出决定。
- 最大化器向左:现在轮到最小化器了。最小化器现在可以在 3 和 5 之间进行选择。作为最小化器,它肯定会在两者中选择最少的,即 3
- 最大化器正确:现在轮到最小化器了。最小化者现在可以在 2 和 9 之间进行选择。他会选择 2,因为它是两个值中最小的。
作为最大化者,您将选择较大的值 3。因此,最大化者的最佳移动是向左移动,最佳值是 3。
现在游戏树如下所示:
上面的树显示了最大化器向左和向右移动时的两个可能的分数。
注意:即使右子树上的值为 9,最小化器也永远不会选择它。我们必须始终假设我们的对手发挥最佳。
下面是相同的实现。
C++
// A simple C++ program to find
// maximum score that
// maximizing player can get.
#include
using namespace std;
// Returns the optimal value a maximizer can obtain.
// depth is current depth in game tree.
// nodeIndex is index of current node in scores[].
// isMax is true if current move is
// of maximizer, else false
// scores[] stores leaves of Game tree.
// h is maximum height of Game tree
int minimax(int depth, int nodeIndex, bool isMax,
int scores[], int h)
{
// Terminating condition. i.e
// leaf node is reached
if (depth == h)
return scores[nodeIndex];
// If current move is maximizer,
// find the maximum attainable
// value
if (isMax)
return max(minimax(depth+1, nodeIndex*2, false, scores, h),
minimax(depth+1, nodeIndex*2 + 1, false, scores, h));
// Else (If current move is Minimizer), find the minimum
// attainable value
else
return min(minimax(depth+1, nodeIndex*2, true, scores, h),
minimax(depth+1, nodeIndex*2 + 1, true, scores, h));
}
// A utility function to find Log n in base 2
int log2(int n)
{
return (n==1)? 0 : 1 + log2(n/2);
}
// Driver code
int main()
{
// The number of elements in scores must be
// a power of 2.
int scores[] = {3, 5, 2, 9, 12, 5, 23, 23};
int n = sizeof(scores)/sizeof(scores[0]);
int h = log2(n);
int res = minimax(0, 0, true, scores, h);
cout << "The optimal value is : " << res << endl;
return 0;
}
Java
// A simple java program to find maximum score that
// maximizing player can get.
import java.io.*;
class GFG {
// Returns the optimal value a maximizer can obtain.
// depth is current depth in game tree.
// nodeIndex is index of current node in scores[].
// isMax is true if current move is of maximizer, else false
// scores[] stores leaves of Game tree.
// h is maximum height of Game tree
static int minimax(int depth, int nodeIndex, boolean isMax,
int scores[], int h)
{
// Terminating condition. i.e leaf node is reached
if (depth == h)
return scores[nodeIndex];
// If current move is maximizer, find the maximum attainable
// value
if (isMax)
return Math.max(minimax(depth+1, nodeIndex*2, false, scores, h),
minimax(depth+1, nodeIndex*2 + 1, false, scores, h));
// Else (If current move is Minimizer), find the minimum
// attainable value
else
return Math.min(minimax(depth+1, nodeIndex*2, true, scores, h),
minimax(depth+1, nodeIndex*2 + 1, true, scores, h));
}
// A utility function to find Log n in base 2
static int log2(int n)
{
return (n==1)? 0 : 1 + log2(n/2);
}
// Driver code
public static void main (String[] args) {
// The number of elements in scores must be
// a power of 2.
int scores[] = {3, 5, 2, 9, 12, 5, 23, 23};
int n = scores.length;
int h = log2(n);
int res = minimax(0, 0, true, scores, h);
System.out.println( "The optimal value is : " +res);
}
}
// This code is contributed by vt_m
C#
// A simple C# program to find maximum score that
// maximizing player can get.
using System;
public class GFG
{
// Returns the optimal value a maximizer can obtain.
// depth is current depth in game tree.
// nodeIndex is index of current node in scores[].
// isMax is true if current move is of maximizer, else false
// scores[] stores leaves of Game tree.
// h is maximum height of Game tree
static int minimax(int depth, int nodeIndex, bool isMax,
int []scores, int h)
{
// Terminating condition. i.e leaf node is reached
if (depth == h)
return scores[nodeIndex];
// If current move is maximizer, find the maximum attainable
// value
if (isMax)
return Math.Max(minimax(depth+1, nodeIndex*2, false, scores, h),
minimax(depth+1, nodeIndex*2 + 1, false, scores, h));
// Else (If current move is Minimizer), find the minimum
// attainable value
else
return Math.Min(minimax(depth+1, nodeIndex*2, true, scores, h),
minimax(depth+1, nodeIndex*2 + 1, true, scores, h));
}
// A utility function to find Log n in base 2
static int log2(int n)
{
return (n==1)? 0 : 1 + log2(n/2);
}
// Driver code
static public void Main ()
{
// The number of elements in scores must be
// a power of 2.
int []scores = {3, 5, 2, 9, 12, 5, 23, 23};
int n = scores.Length;
int h = log2(n);
int res = minimax(0, 0, true, scores, h);
Console.WriteLine( "The optimal value is : " +res);
}
}
// This code is contributed by ajit.
Python3
# A simple Python3 program to find
# maximum score that
# maximizing player can get
import math
def minimax (curDepth, nodeIndex,
maxTurn, scores,
targetDepth):
# base case : targetDepth reached
if (curDepth == targetDepth):
return scores[nodeIndex]
if (maxTurn):
return max(minimax(curDepth + 1, nodeIndex * 2,
False, scores, targetDepth),
minimax(curDepth + 1, nodeIndex * 2 + 1,
False, scores, targetDepth))
else:
return min(minimax(curDepth + 1, nodeIndex * 2,
True, scores, targetDepth),
minimax(curDepth + 1, nodeIndex * 2 + 1,
True, scores, targetDepth))
# Driver code
scores = [3, 5, 2, 9, 12, 5, 23, 23]
treeDepth = math.log(len(scores), 2)
print("The optimal value is : ", end = "")
print(minimax(0, 0, True, scores, treeDepth))
# This code is contributed
# by rootshadow
Javascript
输出:
The optimal value is: 12
本文的思路是通过一个简单的例子来介绍Minimax。
- 在上面的例子中,一个玩家只有两个选择。一般来说,可以有更多的选择。在这种情况下,我们需要重复所有可能的移动并找到最大值/最小值。例如,在 Tic-Tax-Toe 中,第一个玩家可以进行 9 种可能的移动。
- 在上面的例子中,分数(游戏树的叶子)是给我们的。对于典型的游戏,我们需要推导出这些值
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。