学了一下比较简单的博弈模型的常规求解方式,发现就是爆搜。顺便学了有启发式思想的 Alpha-Beta 剪枝,现在觉得是玄学……可能还是记搜比较靠谱?
1 对抗搜索
……然而其实就是搜索。每次大概就是记录一下双方的决策结果和(哈希之后的)局面,然后改谁走谁走就完了。伪代码大概可以这么写:
1 | Function doMax(State S){ |
大概就是交替迭代的思想。
考虑一棵博弈树,节点承载的信息是局面 。那么对于一个零和博弈游戏,双方必然是让自己得益更多,于是考虑转化一下,令局面的分数为「先手的分数 - 后手的分数」,那么先手就是最大化局面分数,后手则是最小化。
于是定义轮到最大化局面分数一方走的局面节点叫做 $\boldsymbol{Max}$节点,轮到最小化局面分数一方走的局面节点叫做 $\boldsymbol{Min}$节点 。那么显然在博弈树上同类节点集合是一个独立集。这种博弈也叫做 零和博弈完全信息公平博弈 ,双方的目的均是 最值化局面分数。
2 Alpha-Beta 剪枝
然后这东西就是一个剪枝,给每个节点一个 $\alpha$ 下界和 $\beta$ 上界。类比状态转移,考虑相邻的状态,大致如下:
假设当前节点为 $\boldsymbol{Max}$ 节点,那么如果存在一种决策使得该 $\boldsymbol{Max}$ 状态的分数 $>$ 上一层决策的分数上限 $\beta’$,那么当前节点的父亲节点,$\boldsymbol{Min}$ 状态,就一定不会做出某些决策,使得局面变成当前的 $\boldsymbol Max$ 决策。
假设当前节点为 $\boldsymbol{Min}$ 节点,那么如果存在一种决策使得该 $\boldsymbol{Min}$ 状态的分数 $<$ 上一层决策的分数下限 $\alpha’$,那么当前节点的父亲节点,$\boldsymbol{Max}$ 状态,就一定不会做出某些决策,使得局面变成当前的 $\boldsymbol Min$ 决策。
于是我们记录 $\alpha$ 值为每个 $\boldsymbol{Max}$ 状态的得分下界,$\beta$ 值为每个 $\boldsymbol{Min}$ 状态的得分下界。初始为 $\alpha=-\infty,\beta=+\infty$
考虑优化的意义。当前状态的分支可能有很多,但是如果在搜第一个分支的时候就发现已经有 $\alpha_n>\beta_{fa_n}$ 了,那么 $fa_n$ 就一定不会走这个决策(毕竟最次也可以让对方得益),于是剩下的分支就不用再搜了。
显然,这种决策是启发性的。同时有以下特点:
决策顺序影响时间效率。如果每次搜都在第一次跳出自然可以让时间上做到最优,但是如果每次都在最后一次跳出就是压根没剪。
不可以裸的记忆化。考虑每个节点如果要记忆化,记下来的应该是当前状态能扩展到的最优局面。但是 Alpha-Beta 剪枝的目的就是在未得到这个点的最优决策时,已经知道该不该继续走。
然后就是伪代码:
1 | Function doMax(State S, Value alpha, Value beta){ |
但是这样的话,我们顶多是能快速计算谁赢谁输而不是赢多少/输多少。于是考虑魔改一下:
版本一:某一方获利最多。参考题目:[九省联考]一双木棋,可以拿到 $70pts$
其实就是修改一下终态的返回值。
1 | int battle(int dep, int x, int y, int alp, int bet, int sa, int sb){ |
版本二:败方存活时间最长。参考题目:[CQOI2013]棋盘游戏,可以拿到 $40pts$
这种的话就直接返回 $-1^{\text{胜方}}\times \text{深度}$ 即可,最大化的就是败方存活的最大深度。
1 | int dfs(int xa, int ya, int xb, int yb, bool w, int step, int alp, int bet){ |
3 两道例题
uva好啊。
$(1$ UVA10111 Find the Winning Move
两人下 $4\times 4$ 的井字棋,给出一个残局,问是否有先手必胜策略。
井字棋:必须要四子连珠才能赢。
这东西只问赢没赢,于是就可以愉快地把局面分数赋为 $1/-1$。搜就完事了233
1 |
|
$(2$ UVA751 Triangle War
给出 $10$ 个点,共有 $18$ 条边,每次 $A,B$ 两个人轮流加入一条边。A先加。
如果形成一个三角形,则三角形归他所有,而且还必须再走一步。最后三角形多的人胜。
现在已经给出一部分已经完成的步数,由于两位玩家都是最聪明的,他们都会走为自己带来最大优势的步数。你需要判断谁会赢得游戏。
一道憨憨题。发现可以直接状压且每个询问图不变,所以果断打开题解找到思路差不多的把打的表copy过来手推。然后其实就是一开始先把初始状态走完,然后因为一共九个三角形,所以如果一方比另一方多 $5$ 个游戏就结束了,于是发现可以把这个差值当做局面分数,搜就完事了。
还有一个烂大街的 $trick$,按秩转移每条边于是想到 $\rm lowbit$。
1 |
|
总结
学这个就图一乐。想得高分请记搜/kel。