CF1201E2 - Knightmare (hard)
题目大意
\(n\times m(2|n,2|m)\)的棋盘上有两个象分别位于\(S_1=(x_1,y_1),S_2=(x_2,y_2)\)
他们分别要到达\(T_1=(\frac{n}{2},\frac{m}{2}),T_2=(\frac{n}{2}+1,\frac{m}{2})\)
一方胜利的情况是:
1.吃掉另一方
2.到达自己的目标位置,且这个位置不能被另一方吃掉
你可以选定操作先手还是后手,要求和交互器交互,并且在350步内取胜
分析
首先是一个重要的性质:双方必然有一方永远无法吃掉另一方
考虑象棋的移动,每次\((x\pm 1,y\pm 2)\)或者\((x\pm 2,y\pm 1)\)
每次操作,必然导致\(x+y\mod 2\)改变,在双方轮流操作的过程中
必然有一方走的时候永远无法和另一方同奇偶,也就是无法吃掉另一方
在此基础上,考虑几种情况
设\(D(a,b)\)为\(a,b\)两点的距离,\(f\)为先手是否永远不会被吃
1.先手可以在不被后手吃掉的情况下到达目标,且先于后手
先于后手即\(D(S_1,T_1)\leq D(S_2,T_2)\)
先手不被后手吃掉的情况
1.\(f\) : 显然
2.\(D(S_1,T_1)<D(S_2,T_1)\):
此时,假设后手存在一个吃掉先手的策略
那么后手经过这个吃掉先手的点到达\(T_1\)的最短路一定和先手相同,故矛盾
2.后手可以在不被先手吃掉的情况下到达目标,且先于先手
\(D(S_1,T_1)>D(S_2,T_2)\)
对称情况
1.\(not\ f\)
2.\(D(S_2,T_2)<D(S_1,T_2)-1\)
以上两种情况均直接冲最短路到达目标
3.双方均无法安全直接抵达目标
此时,考虑选择不会被吃的一方操作
由于自己是无敌的,可以考虑先猛扑对方的终点
3.1 \(f=true\),选择先手
先走到\(T_2\)堵住后手,然后可以绕三步到达\(T_1\)
先手占据\(T_2\)时,后手无法到达\(T_2\)
走第一步时,由于先手限制着,后手无法进入\(T_2\)
走第二步时,根据奇偶性分析,后手无法到达\(T_2\)的奇偶性
第三步到达目标
3.2\(f=false\),同理
实现
可以好好封装一下
我曾经以为不用读入
由于交互器下面读入的参数可能会让交互器走智障操作
如果能吃掉对方,一定要直接吃掉
const int N=1010,INF=1e9+10;
const int dx[]={1,1,-1,-1,2,2,-2,-2};
const int dy[]={2,-2,2,-2,1,-1,1,-1};
int n,m,opt;
int x=-2,y=-2;
void input(){
x=rd(),y=rd();
if(x==-1) exit(0);
}
void CB(){ puts("BLACK"),fflush(stdout),input(); }
void CW(){ puts("WHITE"),fflush(stdout); }
struct Bfser{
int dis[N][N],pre[N][N];
int QX[N*N],QY[N*N],L,R;
int u,v;
int Reach() {
int a=abs(u-x),b=abs(y-v);
if(a>b) swap(a,b);
return a==1 && b==2;
}
void Bfs(int x,int y){
u=x,v=y;
QX[L=R=1]=x,QY[1]=y,pre[x][y]=-1,dis[x][y]=1;
for(;L<=R;) {
x=QX[L],y=QY[L++];
rep(i,0,7) {
int x1=x+dx[i],y1=y+dy[i];
if(x1<1 || y1<1 || x1>n || y1>m || dis[x1][y1]) continue;
dis[x1][y1]=dis[x][y]+1,QX[++R]=x1,QY[R]=y1,pre[x1][y1]=i;
}
}
}
void Go(int d,int k=1) {
if(Reach()) printf("%d %d\n",x,y),fflush(stdout),exit(0);
printf("%d %d\n",u+=dx[d],v+=dy[d]),fflush(stdout);
if(k) input();
}
void Go(int x,int y,int k) {
vector <int> s;
while(~pre[x][y]) {
int t=pre[x][y];
s.pb(t),x-=dx[t],y-=dy[t];
}
drep(i,s.size()-1,0) Go(s[i],k+i);
}
} B,W;
int main(){
n=rd(),m=rd();
int x1=rd(),y1=rd(),x2=rd(),y2=rd();
W.Bfs(x1,y1),B.Bfs(x2,y2);
int f=((x1+y1)&1)!=((x2+y2)&1);
if(W.dis[n/2][m/2]<=B.dis[n/2+1][m/2] && (f || W.dis[n/2][m/2]<B.dis[n/2][m/2])) {
CW(),x=x2,y=y2,W.Go(n/2,m/2,0);
} else if(B.dis[n/2+1][m/2]<W.dis[n/2][m/2] && (B.dis[n/2+1][m/2]<W.dis[n/2+1][m/2]-1 || !f)) {
CB(),B.Go(n/2+1,m/2,0);
} else if(f) {
CW(),x=x2,y=y2,W.Go(n/2+1,m/2,1);
W.Go(2),W.Go(5),W.Go(7,0);
} else {
CB(),B.Go(n/2,m/2,1);
B.Go(0),B.Go(7),B.Go(5,0);
}
}