zoukankan      html  css  js  c++  java
  • CF1201E2

    CF1201E2 - Knightmare (hard)

    题目大意

    (n imes m(2|n,2|m))的棋盘上有两个 马 (Knight是国际象棋) 分别位于(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步内取胜


    分析

    首先是一个重要的性质:双方必然有一方永远无法吃掉另一方

    考虑象棋的移动,每次((xpm 1,ypm 2))或者((xpm 2,ypm 1))

    每次操作,必然导致(x+ymod 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
    ",x,y),fflush(stdout),exit(0);
    		printf("%d %d
    ",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);
    	}
    }
    
  • 相关阅读:
    Mysql 数据类型
    C++ 11 std::function std::bind使用
    C++ 11 Lambda表达式
    C++ 11 nullptr关键字
    C++ 11 auto关键字
    C++ 11 创建和使用共享 weak_ptr
    C++ 11 创建和使用 unique_ptr
    C++ 11 创建和使用 shared_ptr
    VS15 Visual Assist X破解
    开发人员看测试之细说JBehave
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14744488.html
Copyright © 2011-2022 走看看