1、部分概念
1、零和游戏(Zero-sum Game):你死我活,一方胜利代表另一方失败。
2、完全信息(Perfect Information):玩家知道之前所有的步骤。比如象棋。
2、开始游戏
Max代表自己,Min代表对手,通过树状图的方式把每种可能列出来
我们要对每一个结果给一个分数,这个分数是对“我”而言的,站在我的角度上的分数。就是Utility的返回值。赢了就是+1,输了就是-1,平局为0;所以“我”希望最大化这个分数,同时对手得分最小化。
就上图所示的两层博弈树,我们按照极小极大算法的方式进行展开:
刚开始除叶子结点外其他的都没有值
1、从MAX出发,进行深度优先搜索,到达左子树低端的叶子结点,Utility=3;
2、上图中,叶子结点往上是MIN,也就是MIN行棋最优解—>是它孩子中最小的那个:3
3、比较B的所有孩子,将最小的值、对MIN行棋最优的收益“3”赋值给B
4、按照同样的方法搜索其他子树C、D,可以得到C=2,D=2
5、MIN表示完之后向上一层(MAX行棋)进军,MAX的最优解是下一步的收益最大的时候,也就是MIN层中最大的那一个——A=3
MAX向下执行时,会找让Utility最大的行棋;MIN向下执行时,会找让Utility最小的行棋
3、伪码表示:
先说明几个函数:
:初始状态,规范游戏开始时的情况。
: 定义此时该谁行动。
: 返回此状态下的合法移动集合。
: 转移模型
: 终止测试,游戏结束返回真,否则返回假。结束状态称为终止状态
: 效用函数
: 找出集合S中有最大f(a)值的a
//假设对手很强,每次也能走到自己的最好方案上。这一步体现在为结点赋值上。
//算法将给出全部的行棋方式。
function MINIMAX-DECISION(state)returns an action //给定一个开始状态
return arg max(a∈ACTIONS(s))MIN-VALUE(RESULT(state,a))
//下一步的MIN也会找到它自己的最优解,但是我们自己的最大收益取决于对手最坏的情况,所以MAX的返回值是对手行棋里面最差的一步,
function MAX-VALUE(state)returns a utility value
if TERMINAL-TEST(state)then return UTILITY(state) //终止测试
v ← ∞
for each a in ACTIONS(state) do
v ← MAX(v,MIN-VALUE(RESULT(s,a)))
return v;
//为对手找到最优解,当前这个结点的收益值就是“我”下一步的收益里面最小的那一个。
function MIN-VALUE(state)returns a utility value
if TERMINAL-TEST(state)then return UTILITY(state)
v ← ∞
for each a in ACTIONS(state) do
v ← MIN(v,MAX-VALUE(RESULT(s,a)))
return v; //这就是当前MIN结点的值,孩子结点中最小的一个
不难发现,极小极大算法对博弈树进行了一次深度优先搜索,如果树的深度为,每个节点的合法行棋有个,那么极小极大算法的时间复杂度为 、一次性生成所有的后继,空间复杂度为、一次只生成一个后继那么空间复杂度为
α-β搜索算法
1、α-β剪枝
由于极小极大算法呈指数级增长,无法消除,不过可以将其减半——可能不需要遍历博弈树的每一个结点就能算出正确的极大极小值。
重新观察上文中所说到的两层决策树
(a) B的第一个叶节点为3,则MIN至多为3;
(b) B的第二个叶节点为12,B仍至多为3;
© B的第三个叶节点为8,B确定为3 (都遍历完了嘛)。
(d) C的第一个叶节点为2,则C至多为2(此时根节点的最小取值为3,比C最大取值还大,所以C就不用再考虑了,他不可能是MAX选择的对象了)
(e) D的第一个叶节点为14,D至多为14,D现在的可取区间为[-
MAX取下一层中的最大的一个数为自己的值,由B、C两点我们可以推出A最小为3,现在D的范围是[-
(f) 展开第二个节点,D的范围变成了[-
利用公式来描述上面的过程,设C中没有展开的子结点分别为和:
与的取值并不会影响最终的结果以及因此作出的决策树。
2、算法表示
值得注意的是,极小极大算法是深度优先的,任何时候只考虑某条单一的路径上的结点。
到目前为止路径上发现的MAX最佳(极大值)选择
到目前为止路径上发现的MIN最佳(极小值)选择
function ALPHA-BETA-SEARCH(state) returns an action
v <-- MAX-VALUE(state, Negative infinity, Positive infinity)
return the action in ACTION(state)with value v
function MAX-VALUE(state, α, β)returns an utility value
if TERMINAL-TEST(state)then return UTILITY(state) //终止测试
v ← -∞
for each a in ACTIONS(state) do
v ← MAX(v,MIN-VALUE(RESULT(s,a), α, β ))
if v >= β then return v //
α <-- MAX(α, v)
return v;
function MIN-VALUE(state, α, β)returns an utility value
if TERMINAL-TEST(state)then return UTILITY(state) //终止测试
v ← +∞
for each a in ACTIONS(state) do
v ← MIN(v,MAX-VALUE(RESULT(s,a), α, β ))
if v <= α then return v //
β <-- MAX(β, v)
return v;
3、行棋排序
α-β剪枝剪枝的效率很大程度上依检查后继状态的顺序。在图“博弈树的最优决策过程中”的e和f部分,我们无法剪去任何后继,因为生成的都是最差的后继,如果能先生成第三个后继,我们就能顺利减掉其他两个,如果这样做,算法只需要检查 个结点就能作出决策,深度为 ,分支因子为 。
如果后继不采用最佳优先的顺序而是随机顺序那么算法要检查的总结点数增加到