跳转至

博弈

773 个字 18 行代码 预计阅读时间 3 分钟

Minimax 搜索

我方是绿色:越大越好 对方是红色:越小越好

最朴素的方法就是从叶子节点向上回溯

Minimax 算法又叫极小化极大算法,是一种找出失败的最大可能性中的最小值的算法。

在局面确定的双人对弈里,常进行对抗搜索,构建一棵每个节点都为一个确定状态的搜索树。奇数层为己方先手,偶数层为对方先手。搜索树上每个叶子节点都会被赋予一个估值,估值越大代表我方赢面越大。我方追求更大的赢面

来看一个简单的例子。

称我方为 MAX,对方为 MIN,图示如下:

例如,对于如下的局势,假设从左往右搜索,根节点的数值为我方赢面:

我方应选择中间的路线。因为,如果选择左边的路线,最差的赢面是 3;如果选择中间的路线,最差的赢面是 15;如果选择右边的路线,最差的赢面是 1。虽然选择右边的路线可能有 22 的赢面,但对方也可能使我方只有 1 的赢面,假设对方会选择使得我方赢面最小的方向走,那么经过权衡,显然选择中间的路线更为稳妥。

实际上,在看右边的路线时,当发现赢面可能为 1 就不必再去看赢面为 12、20、22 的分支了,因为已经可以确定右边的路线不是最好的。

分析

性能:

  • 完备性:Yes,如果树有限
  • 最优性:Yes
  • 时间复杂性:\(O(b^m)\)
  • 空间复杂性:\(O(bm)\)

极大极小算法将所有子树全部扫描,极其浪费时间和空间

alpha-beta 剪枝算法

MinMax 算法的优化,产生的结果完全相同,但运行效率不一样

基本思想:根据上一层已经得到的当前最优结果,决定目前的搜索是否要继续下去

两个假设:

  • 整个博弈属于零和博弈,即一方的收益必然意味着另一方的损失
  • 博弈双方足够聪明,即每一方在决策时总会选择使自己利益最大化的决策

算法流程详见:https://oi-wiki.org/search/alpha-beta/

  • 对于 Max 层,本体值为 \(\alpha\);对于 Min 层,本体值为 \(\beta\)
  • 初始情况均为 \(\alpha=-\inf,~\beta=+\inf\)
  • 按照先序遍历的顺序
  • 向上传递:更新本体值
  • 向下传递:复制 \(\alpha\)\(\beta\) 的值到子节点
  • 若在某一节点更新后出现 \(\alpha>\beta\),则其后面不需要再进行更新,直接剪枝即可

分析

  • 剪枝不会影响最终结果
  • 剪枝效率很大程度上取决于检查后继的顺序
  • 理想排序下先检查可能最好的后继,时间复杂度从 \(O(b^m)\) 降低到 \(O(b^{m/2})\)

实现

参考代码
int alpha_beta(int u, int alph, int beta, bool is_max) {
  if (!son_num[u]) return val[u];
  if (is_max) {
    for (int i = 0; i < son_num[u]; ++i) {
      int d = son[u][i];
      alph = max(alph, alpha_beta(d, alph, beta, !is_max));
      if (alph >= beta) break;
    }
    return alph;
  } else {
    for (int i = 0; i < son_num[u]; ++i) {
      int d = son[u][i];
      beta = min(beta, alpha_beta(d, alph, beta, !is_max));
      if (alph >= beta) break;
    }
    return beta;
  }
}

蒙特卡洛树搜索

参考资料

详解 Minimax 算法与 α-β 剪枝 -CSDN 博客

y_lz 的笔记本