学习对抗搜索的第一篇题解记录。
对抗搜索
定义
竞争环境中多个玩家之间的目标是有冲突的,称为对抗搜索问题。
特点
-
确定的、完全可查的环境。
-
智能体轮流行动。
-
零和博弈。
-
每一步行动的结果确定。
分析
结合本题进行讲解。
分析可以发现,当一开始如果双方是相邻的,自然是先手获胜。否则,后手一定获胜,感性的理解是:后手总能将先手逼到一个角落使先手必败。
于是我们的做法是:
一开始如果双方是相邻的直接输出先手胜。
否则,先手的目标是尽量拖延自己的生存时间,后手的目标是尽快击败对手。
由上述特征,可知这是一个对抗搜索问题。
具体来讲,就是在搜索的过程中,如果轮到先手决策,那就尽可能地转移到生存时间最长的状态。而轮到后手决策时则尽可能地转移到最快击败对手的状态。
结合代码理解(很短的hh)
#include<bits/stdc++.h>
using namespace std;
// 因为 luogu 的 y1 会导致 CE,因此可以 #define 一个其他名字。
#define y1 Tenshi
const int N=21, INF=0x3f3f3f3f;
int n, x1, y1, x2, y2;
int f[2][65][N][N][N][N]; // 记录状态
// 控制四个方向
int dx[]={-1, 1, 0, 0};
int dy[]={0, 0, -1, 1};
int dfs(bool ok, int cnt, int x1, int y1, int x2, int y2){
if(~f[ok][cnt][x1][y1][x2][y2]) return f[ok][cnt][x1][y1][x2][y2];
if(cnt>3*n) return f[ok][cnt][x1][y1][x2][y2]=INF;
if(x1==x2 && y1==y2) return f[ok][cnt][x1][y1][x2][y2]=(ok? 0: INF);
int res;
if(ok){ // 先手
res=-1;
for(int i=0; i<4; i++){
int kx=x1+dx[i], ky=y1+dy[i];
if(kx<1 || kx>n || ky<1 || ky>n) continue;
res=max(res, dfs(0, cnt+1, kx, ky, x2, y2));
}
}
else{ // 后手
res=INF;
for(int i=0; i<4; i++){
for(int j=1; j<=2; j++){
int kx=x2+j*dx[i], ky=y2+j*dy[i];
if(kx<1 || kx>n || ky<1 || ky>n) continue;
res=min(res, dfs(1, cnt+1, x1, y1, kx, ky));
}
}
}
return f[ok][cnt][x1][y1][x2][y2]=res+1;
}
int main(){
memset(f, -1, sizeof f);
cin>>n>>x1>>y1>>x2>>y2;
if(abs(x1-x2)+abs(y1-y2)==1) puts("WHITE 1");
else cout<<"BLACK "<<dfs(1, 0, x1, y1, x2, y2)<<endl;
return 0;
}