#博弈论,拓扑排序#洛谷 9169 [省选联考 2023] 过河卒

题目传送门


分析

状态是三个点,两个红点可以用行优先压缩,并且只有与起点状态奇偶性相同的才会被起点经过。

所以一共就 \(nm\binom{nm}{2}\) 个状态,建反图先手必胜当且仅当后手有一个后继状态必败;

先手必败当且仅当后手所有后继状态必胜(这里需要拓扑排序),同样拓扑排序就能让步数尽量大。


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int N=500011,M=11,dx[4]={0,0,1,-1},dy[4]={1,-1,0,0}; queue<int>q; char s[M][M]; vector<int>G[N];
int n,m,tot,blackx,blacky,red0x,red0y,red1x,red1y,sum,S,rk[M][M][M][M][M][M],draw[N],Odd[N],deg[N],dis[N],win[N];
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
bool block(int i1,int j1,int i2,int j2,int i3,int j3){
	if (i1<1||i2<1||i3<1||j1<1||j2<1||j3<1) return 1;
	if (i1>n||i2>n||i3>n||j1>m||j2>m||j3>m) return 1;
	if (s[i1][j1]=='#'||s[i2][j2]=='#'||s[i3][j3]=='#'||(i2==i3&&j2==j3)) return 1;
	return 0;
}
int Abs(int x){return x<0?-x:x;}
bool odd(int i1,int j1,int i2,int j2,int i3,int j3){return Abs(sum-i1-j1-i2-j2-i3-j3)&1;}
int main(){
	iut();
	for (int T=iut();T;--T){
		n=iut(),m=iut(),tot=0;
		for (int i=1;i<=n;++i){
			char ch=getchar();
			for (int j=1;j<=m;++j){
				while (ch!='O'&&ch!='X'&&ch!='#'&&ch!='.') ch=getchar();
				s[i][j]=ch,ch=getchar();
			}
			for (int j=1;j<=m;++j)
			if (s[i][j]=='O') red0x=red1x,red0y=red1y,red1x=i,red1y=j;
			    else if (s[i][j]=='X') blackx=i,blacky=j;
		}
		sum=blackx+blacky+red0x+red0y+red1x+red1y;
		for (int i1=1;i1<=n;++i1)
		for (int j1=1;j1<=m;++j1)
		for (int i2=1;i2<=n;++i2)
		for (int j2=1;j2<=m;++j2)
		for (int i3=i2;i3<=n;++i3)
		for (int j3=(i2==i3?(j2+1):1);j3<=m;++j3)
		if (!block(i1,j1,i2,j2,i3,j3))
			rk[i1][j1][i2][j2][i3][j3]=++tot;
		S=rk[blackx][blacky][red0x][red0y][red1x][red1y];
		for (int i=1;i<=tot;++i) draw[i]=1;
		for (int i1=1;i1<=n;++i1)
		for (int j1=1;j1<=m;++j1)
		for (int i2=1;i2<=n;++i2)
		for (int j2=1;j2<=m;++j2)
		for (int i3=i2;i3<=n;++i3)
		for (int j3=(i2==i3?(j2+1):1);j3<=m;++j3)
		if (!block(i1,j1,i2,j2,i3,j3)){
			int now=rk[i1][j1][i2][j2][i3][j3];
			if (odd(i1,j1,i2,j2,i3,j3)){
				Odd[now]=1;
				for (int k=0;k<4;++k){
					int I2=i2+dx[k],J2=j2+dy[k];
					if (!block(i1,j1,I2,J2,i3,j3)){
						if (I2>i3||(I2==i3&&J2>j3)) G[now].push_back(rk[i1][j1][i3][j3][I2][J2]);
						   else G[now].push_back(rk[i1][j1][I2][J2][i3][j3]);
					}
				}
				for (int k=0;k<4;++k){
					int I3=i3+dx[k],J3=j3+dy[k];
					if (!block(i1,j1,i2,j2,I3,J3)){
						if (i2>I3||(i2==I3&&j2>J3)) G[now].push_back(rk[i1][j1][I3][J3][i2][j2]);
						   else G[now].push_back(rk[i1][j1][i2][j2][I3][J3]);
					}
				}
			}else{
				Odd[now]=0;
				for (int k=0;k<3;++k){
					int I1=i1+dx[k],J1=j1+dy[k];
					if (!block(I1,J1,i2,j2,i3,j3))
						G[now].push_back(rk[I1][J1][i2][j2][i3][j3]);
				}
			}
		}
		for (int i1=1;i1<=n;++i1)
		for (int j1=1;j1<=m;++j1)
		for (int i2=1;i2<=n;++i2)
		for (int j2=1;j2<=m;++j2)
		for (int i3=i2;i3<=n;++i3)
		for (int j3=(i2==i3?(j2+1):1);j3<=m;++j3)
		if (!block(i1,j1,i2,j2,i3,j3)){
			int now=rk[i1][j1][i2][j2][i3][j3];
			sort(G[now].begin(),G[now].end());
			G[now].erase(unique(G[now].begin(),G[now].end()),G[now].end());
			for (int y:G[now]) ++deg[y];
			if (i1==1) draw[now]=dis[now]=0,win[now]=Odd[now];
			else if ((i1==i2&&j1==j2)||(i1==i3&&j1==j3)) draw[now]=dis[now]=0,win[now]=0;
		}
		while (!q.empty()) q.pop();
		for (int i=1;i<=tot;++i){
			if (draw[i]&&!deg[i]) draw[i]=dis[i]=0,win[i]=0;
			if (!draw[i]) q.push(i);
		}
		while (!q.empty()){
			int x=q.front(); q.pop();
			if (x==S) break;
			if (!win[x]){
				for (int y:G[x])
				if (draw[y]){
					win[y]=1,draw[y]=0,--deg[y];
					dis[y]=dis[x]+1,q.push(y);
				}
			}else{
				for (int y:G[x])
				if (draw[y]&&--deg[y]==0){
					win[y]=0,draw[y]=0;
					dis[y]=dis[x]+1,q.push(y);
				}
			}
		}
		if (draw[S]) printf("Tie\n");
		else if (win[S]) printf("Red %d\n",dis[S]);
		    else printf("Black %d\n",dis[S]);
		for (int i=1;i<=tot;++i) draw[i]=win[i]=dis[i]=deg[i]=Odd[i]=0;
		for (int i=1;i<=tot;++i) G[i].erase(G[i].begin(),G[i].end());
	}
	return 0;
}
posted @ 2025-07-02 09:08  lemondinosaur  阅读(13)  评论(0)    收藏  举报