知识点-极大极小搜索+alpha_beta剪枝
解决问题
博弈类游戏
概要
其实就是用深度搜索搜索博弈的策略,博弈中两个人轮流进行游戏,在算法里转化为在搜索的不同深度下选取不同的搜索策略,一般是奇数层选择值值最大的策略,对应第一个人要让自己的收益最大,而偶数层选择值最小的策略,因为第二个人想要赢的话,必定是要让对手的收益最小
下面用一个经典的问题举个例子:你可以选择你朋友手里的两个钱包中的其中一个,然后你的朋友会从这个钱包里面拿出一张钱给你,你当然希望拿到的钱越多越好,而你的朋友希望给出的钱越少越好,假设两个钱包里面分别有面额为2、4的钱和1、3的钱,那么搜索树的样子就会是下面这样,交替取max和min
而alpha_beta剪枝其实就是针对这种极大极小搜索的剪枝,alpha是第一个人期望得到的最大收益,初始设为-INF,而beta是对手能接受的最小收益,初始设为INF。而这个剪枝就是在搜索max层时,若是当前搜索的min层子树已经搜到一个比alpha值小的分叉,那么剩余的分叉就都不需要搜了,因为在min层里面是取最小值的,而目前的最小值比已经找到的最大值要小了,那么继续搜索下去也是同样无法更新最大值,所以就进行剪枝。在min层也是这样根据beta值剪枝
例如上面那个例子,在搜完左边的子树之后,alpha更新为2,然后在搜索右边的子树时,左边分叉直接找到了一个1,那么在右边的分叉不管是什么值,它不可能会让最后取到的值大于1,也就不可能大于2,所以实际上搜到这里已经确定了答案是2,所以接下来的3就不需要再去访问了
例题
POJ1085
参考代码
int alpha_beta(int player, int cur_state, int alpha, int beta, int ca, int cb)
{
int remain;
// 如 A 得到 5 分以上则 A 赢
// 如 B 得到 5 分以上则 A 输
if(ca >= 5) return 1;
if(cb >= 5) return -1;
remain = ((~cur_state) & end_state); // 计算剩余可走的边
if(player){ // A 走
while(remain){ // 有可走边
int move = (remain & (-remain)); // 选择一条可走边
int ta = ca;
int val;
// A 填了边后形成新的局面
int new_state = next_state(cur_state, move, &ta);
if(ta > ca) // 如果 A 得分了,则 A 继续填一条边
val = alpha_beta(player, new_state, alpha, beta, ta, cb);
else // 否则轮到 B 填
val = alpha_beta(player^1, new_state, alpha, beta, ca, cb);
if(val > alpha)
alpha = val;
if(alpha >= beta) //剪枝
return alpha;
remain -= move; // 把边 move 从剩余可选边 remain 中移除
}
return alpha;
}
else{ // B 走
while(remain){
int move = (remain & (-remain));
int tb = cb;
int val;
int new_state = next_state(cur_state, move, &tb);
if(tb > cb)
val = alpha_beta(player, new_state, alpha, beta, ca, tb);
else
val = alpha_beta(player^1, new_state, alpha, beta, ca, cb);
if(val < beta)
beta = val;
if(alpha >= beta)
return beta;
remain -= move;
}
return beta;
}
}