【对抗搜索】P4576 [CQOI2013]棋盘游戏

学习对抗搜索的第一篇题解记录。

对抗搜索

定义

竞争环境中多个玩家之间的目标是有冲突的,称为对抗搜索问题。

特点

  1. 确定的、完全可查的环境。

  2. 智能体轮流行动。

  3. 零和博弈。

  4. 每一步行动的结果确定。

分析

结合本题进行讲解。

分析可以发现,当一开始如果双方是相邻的,自然是先手获胜。否则,后手一定获胜,感性的理解是:后手总能将先手逼到一个角落使先手必败。

于是我们的做法是:

一开始如果双方是相邻的直接输出先手胜。

否则,先手的目标是尽量拖延自己的生存时间,后手的目标是尽快击败对手。

由上述特征,可知这是一个对抗搜索问题。

具体来讲,就是在搜索的过程中,如果轮到先手决策,那就尽可能地转移到生存时间最长的状态。而轮到后手决策时则尽可能地转移到最快击败对手的状态。

结合代码理解(很短的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;
}
posted @ 2021-08-18 13:46  HinanawiTenshi  阅读(55)  评论(0编辑  收藏  举报