算法——结合实例了解Minimax算法(极小化极大算法)
计算机科学中最有趣的事情之一就是编写一个人机博弈的程序。有大量的例子,最出名的是编写一个国际象棋的博弈机器。但不管是什么游戏,程序趋向于遵循一个被称为Minimax算法,伴随着各种各样的子算法在一块。本篇将简要介绍 minimax 算法,并通过实例分析帮助大家更好的理解。
一、概念
Minimax算法又名极小化极大算法,是一种找出失败的最大可能性中的最小值的算法。Minimax算法常用于棋类等由两方较量的游戏和程序,这类程序由两个游戏者轮流,每次执行一个步骤。我们众所周知的五子棋、象棋等都属于这类程序,所以说Minimax算法是基于搜索的博弈算法的基础。该算法是一种零总和算法,即一方要在可选的选项中选择将其优势最大化的选择,而另一方则选择令对手优势最小化的方法。
(1)Minimax是一种悲观算法,即假设对手每一步都会将我方引入从当前看理论上价值最小的格局方向,即对手具有完美决策能力。因此我方的策略应该是选择那些对方所能达到的让我方最差情况中最好的,也就是让对方在完美决策下所对我造成的损失最小。
(2)Minimax不找理论最优解,因为理论最优解往往依赖于对手是否足够愚蠢,Minimax中我方完全掌握主动,如果对方每一步决策都是完美的,则我方可以达到预计的最小损失格局,如果对方没有走出完美决策,则我方可能达到比预计的最悲观情况更好的结局。总之我方就是要在最坏情况中选择最好的。
二、实例分析
实例一、井字棋中的应用
- 游戏规则和局面评估:井字棋是在 3×3 的棋盘上进行的游戏,玩家轮流在空格中放置自己的棋子(假设一方为 X,另一方为 O),率先将自己的三个棋子连成一线(横、竖或斜)的玩家获胜。如果棋盘填满后仍未出现连成一线的情况,则为平局。我们可以为每个局面定义一个评估值:如果 X 获胜,评估值为 + 1;如果 O 获胜,评估值为 - 1;如果是平局,评估值为 0。
- 构建游戏树:以 X 玩家为先手开始构建游戏树。在根节点处,X 玩家有 9 种可能的落子位置,每个位置对应一个子节点。对于每个子节点,O 玩家又有 8 种可能的落子位置,依此类推,直到游戏结束(出现获胜局面或平局)。
- Minimax 算法执行过程
- 叶节点评估:当到达游戏结束的局面(叶节点)时,根据游戏结果赋予评估值,如 X 获胜则评估值为 + 1,O 获胜则为 - 1,平局为 0。
- 回溯计算:从叶节点开始回溯,假设当前轮到 X 玩家(Max 玩家)决策,在其所处的节点,它会选择子节点中评估值最大的那个作为自己的最优策略。若当前轮到 O 玩家(Min 玩家)决策,它会选择子节点中评估值最小的那个。比如,在某个中间节点,X 玩家的三个子节点评估值分别为 - 1、0、1,那么 X 玩家会选择评估值为 1 的子节点对应的走法。
| |
---|---|---| |
---|---|---| |
假设当前棋盘为空,X 玩家考虑第一步的走法。算法会模拟所有可能的后续情况:
- X 选择左上角:然后 O 可能有多种回应,假设 O 选择中心位置。接着 X 再走,可能形成不同局面,继续模拟下去直到游戏结束,得到一个评估值。
- X 选择其他位置:同样依次模拟后续 O 的走法和 X 的应对,直到得出所有以 X 第一步不同走法为根节点的子树的评估值。假设经过计算,X 选择左上角后最终的评估值最高,那么算法就会认为 X 的第一步最优走法是左上角。
局限性和改进方向
- 局限性:Minimax 算法的时间复杂度和空间复杂度较高,随着游戏树的深度和广度增加,计算量呈指数级增长。在复杂的游戏中,如国际象棋、围棋等,可能无法在合理时间内计算出所有可能。
- 改进方向:为了减少计算量,可以采用 α-β 剪枝技术,在搜索过程中剪掉一些不可能影响最终结果的分支。还可以结合启发式函数,对局面进行更快速的评估,减少不必要的搜索深度。
实例二、纸币面值最大化最小
题目:现在考虑这样一个游戏:有三个盘子A、B和C,每个盘子分别放有三张纸币。A放的是1、20、50;B放的是5、10、100;C放的是1、5、20。单位均为“元”。有甲、乙两人,两人均对三个盘子和上面放置的纸币有可以任意查看。
游戏分三步:
(1)甲从三个盘子中选取一个。
(2)乙从甲选取的盘子中拿出两张纸币交给甲。
(3)甲从乙所给的两张纸币中选取一张,拿走。
其中甲的目标是最后拿到的纸币面值尽量大,乙的目标是让甲最后拿到的纸币面值尽量小。
基本思路:一般解决博弈类问题的自然想法是将格局组织成一棵树,树的每一个节点表示一种格局,而父子关系表示由父格局经过一步可以到达子格局。Minimax也不例外,它通过对以当前格局为根的格局树搜索来确定下一步的选择。而一切格局树搜索算法的核心都是对每个格局价值的评价。
解题:下图是上述示例问题的格局树:

注意,由于示例问题格局数非常少,我们可以给出完整的格局树。这种情况下我可以找到Minimax算法的全局最优解。而真实情况中,格局树非常庞大,即使是计算机也不可能给出完整的树,因此我们往往只搜索一定深度,这时只能找到局部最优解。
我们从甲的角度考虑。其中正方形节点表示轮到我方(甲),而三角形表示轮到对方(乙)。经过三轮对弈后(我方-对方-我方),将进入终局。黄色叶结点表示所有可能的结局。从甲方看,由于最终的收益可以通过纸币的面值评价,我们自然可以用结局中甲方拿到的纸币面值表示终格局的价值。
下面考虑倒数第二层节点,在这些节点上,轮到我方选择,所以我们应该引入可选择的最大价值格局,因此每个节点的价值为其子节点的最大值:

这些轮到我方的节点叫做max节点,max节点的值是其子节点最大值。
倒数第三层轮到对方选择,假设对方会尽力将局势引入让我方价值最小的格局,因此这些节点的价值取决于子节点的最小值。这些轮到对方的节点叫做min节点。
最后,根节点是max节点,因此价值取决于叶子节点的最大值。最终完整赋值的格局树如下:

总结一下Minimax算法的步骤:
(1)首先确定最大搜索深度D,D可能达到终局,也可能是一个中间格局。
(2)在最大深度为D的格局树叶子节点上,使用预定义的价值评价函数对叶子节点价值进行评价。
(3)自底向上为非叶子节点赋值。其中max节点取子节点最大值,min节点取子节点最小值。
(4)每次轮到我方时(此时必处在格局树的某个max节点),选择价值等于此max节点价值的那个子节点路径。
在上面的例子中,根节点的价值为20,表示如果对方每一步都完美决策,则我方按照上述算法可最终拿到20元,这是我方在Minimax算法下最好的决策。格局转换路径如下图红色路径所示:

注意几点:
(1)真实问题一般无法构造出完整的格局树,所以需要确定一个最大深度D,每次最多从当前格局向下计算D层。
(2)因为上述原因,Minimax一般是寻找一个局部最优解而不是全局最优解,搜索深度越大越可能找到更好的解,但计算耗时会呈指数级膨胀。
(3)也是因为无法一次构造出完整的格局树,所以真实问题中Minimax一般是边对弈边计算局部格局树,而不是只计算一次,但已计算的中间结果可以缓存。
三、伪代码
def minimax(node, depth, is_maximizing):if depth == 0 or node是终止节点:return 评估值if is_maximizing:value = -∞for child in node的子节点:value = max(value, minimax(child, depth-1, False))return valueelse:value = +∞for child in node的子节点:value = min(value, minimax(child, depth-1, True))return value
四、关键点
-
评估函数:需准确反映局面优劣(如棋子价值、位置优势)。
-
效率优化:实际应用中需结合剪枝(如Alpha-Beta剪枝)减少计算量。
-
深度限制:受计算资源限制,通常设置搜索深度。
总结
Minimax算法通过模拟对手最优策略,为当前玩家提供最稳健的决策。其核心是交替最小化与最大化收益,确保在最坏情况下争取最好结果。虽然理论完备,但实际应用需结合启发式评估和优化策略以提高效率。
相关文章:
算法——结合实例了解Minimax算法(极小化极大算法)
计算机科学中最有趣的事情之一就是编写一个人机博弈的程序。有大量的例子,最出名的是编写一个国际象棋的博弈机器。但不管是什么游戏,程序趋向于遵循一个被称为Minimax算法,伴随着各种各样的子算法在一块。本篇将简要介绍 minimax 算法&#…...
使用 DeepSeek 生成商城流程图
步骤 1.下载 mermaid 2.使用 DeepSeek 生成 mermaid 格式 3.复制内容到 4.保存备用。 结束。...
什么是GraphQL?
如果你在寻找漏洞利用方式,请参考下面的文章 GraphQL API 漏洞 |网络安全学院 GitHub - swisskyrepo/PayloadsAllTheThings: A list of useful payloads and bypass for Web Application Security and Pentest/CTF GraphQL 查询(Query) GraphQL 既不是…...
Spring Boot 的约定优于配置,你的理解是什么?
Spring Boot 的“约定优于配置”:开发效率的革命性提升 在软件开发中,开发者常常需要花费大量时间编写繁琐的配置文件,尤其是在传统的 Java EE 或 Spring 框架中。而 Spring Boot 通过“约定优于配置”(Convention Over Configur…...
C#开源大型商城系统之B2B2C+O2O一体化_OctShop
一、应用背景与引言 在当今数字化商业的浪潮中,电子商务平台的构建成为众多企业拓展业务、提升竞争力的关键举措。C# 语言以其强大的功能、高效的性能以及良好的开发框架支持,在商城系统开发领域占据着重要地位。独立开源的大型 C# 商城系统,…...
gitte远程仓库修改后,本地没有更新,本地与远程仓库不一致
问题 :gitte远程仓库修改后,本地没有更新,本地与远程仓库不一致 现象: [cxqiZwz9fjj2ssnshikw14avaZ rpc]$ git push Username for https://gitee.com: beihangya Password for https://beihangyagitee.com: To https://gitee.c…...
【对比】Pandas 和 Polars 的区别
Pandas vs Polars 对比表 特性PandasPolars开发语言Python(Cython 实现核心部分)Rust(高性能系统编程语言)性能较慢,尤其在大数据集上(内存占用高,计算效率低)极快,利用…...
el-input无法输入0.0001的小数,自动转换为0在vue3中的bug
今天遇到个bug,el-input中只能输入0.1或者输入0.1再加上00成为0.001,不能直接输入0.001,否则自动转换为0。需要去掉 v-model.number后面的 .number 源代码: <el-table-column label"实发数量" width"120"…...
Ubuntu 下 systemd 介绍
系列文章目录 Linux内核学习 Linux 知识(1) Linux 知识(2) WSL Ubuntu QEMU 虚拟机 Linux 调试视频 PCIe 与 USB 的补充知识 vscode 使用说明 树莓派 4B 指南 设备驱动畅想 Linux内核子系统 Linux 文件系统挂载 QEMU 通过网络实现…...
BERT文本分类(PyTorch和Transformers)畅用七个模型架构
(PyTorch)BERT文本分类:七种模型架构 🌟 1. 介绍 使用BERT完成文本分类任务(如情感分析,新闻文本分类等等)对于NLPer已经是很基础的工作了!虽说已迈入LLM时代,但是BERT…...
两步在 Vite 中配置 Tailwindcss
第一步:安装依赖 npm i -D tailwindcss tailwindcss/vite第二步:引入 tailwindcss 更改配置 // src/main.js import tailwindcss/index// vite.config.js import vue from vitejs/plugin-vue import tailwindcss from tailwindcss/viteexport default …...
【vmware虚拟机安装教程】
以下是在VMware Workstation Pro上安装虚拟机的详细教程: 准备工作 下载VMware Workstation Pro 访问VMware官网下载并安装VMware Workstation Pro(支持Windows和Linux系统)。安装完成后,确保已激活软件(试用版或正式…...
文字转语音(三)FreeTTS实现
项目中有相关的功能,就简单研究了一下。 说明 FreeTTS 是一个基于 Java 的开源文本转语音(TTS)引擎,旨在将文字内容转换为自然语音输出。 FreeTTS 适合对 英文语音质量要求低、预算有限且需要离线运行 的场景,但若需…...
string类详解(上)
文章目录 目录1. STL简介1.1 什么是STL1.2 STL的版本1.3 STL的六大组件 2. 为什么学习string类3. 标准库中的string类3.1 string类3.2 string类的常用接口说明 目录 STL简介为什么学习string类标准库中的string类string类的模拟实现现代版写法的String类写时拷贝 1. STL简介 …...
Visual Studio Code使用ai大模型编成
1、在Visual Studio Code搜索安装roo code 2、去https://openrouter.ai/settings/keys官网申请个免费的配置使用...
外贸跨境订货系统流程设计、功能列表及源码输出
在全球化的商业环境下,外贸跨境订货系统对于企业拓展国际市场、提升运营效率至关重要。该系统旨在为外贸企业提供一个便捷、高效、安全的订货平台,实现商品展示、订单管理、物流跟踪等功能,满足跨境业务的多样化需求。以下将详细阐述外贸订货…...
TraeAi上手体验
一、Trae介绍 由于MarsCode 在国内由于规定限制,无法使用 Claude 3.5 Sonnet 模型,字节跳动选择在海外推出 Trae,官网:https://www.trae.ai/。 二、安装 1.下载安装Trae-Setup-x64.exe 2.注册登录 安装完成后,点击登…...
深入解析 vLLM:高性能 LLM 服务框架的架构之美(一)原理与解析
修改内容时间2.4.1处理请求的流程,引用更好的流程图2025.02.11首发2025.02.08 深入解析 vLLM:高性能 LLM 服务框架的架构之美(一)原理与解析 深入解析 vLLM:高性能 LLM 服务框架的架构之美(二)…...
thingboard告警信息格式美化
原始报警json内容: { "severity": "CRITICAL","acknowledged": false,"cleared": false,"assigneeId": null,"startTs": 1739801102349,"endTs": 1739801102349,"ackTs": 0,&quo…...
redis解决高并发看门狗策略
当一个业务执行时间超过自己设定的锁释放时间,那么会导致有其他线程进入,从而抢到同一个票,所有需要使用看门狗策略,其实就是开一个守护线程,让守护线程去监控key,如果到时间了还未结束,就会将这个key重新s…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
tomcat入门
1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效,稳定,易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...
【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error
在前端开发中,JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作(如 Promise、async/await 等),开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝(r…...
