【TC SRM 423 Div1 Level2】TheEasyChase(不平等博弈)(迭代)(SPFA)

传送门


题解:

注意到状态数其实不是很多,也就是说我们可以想办法按照某种顺序处理出所有 O ( n 4 ) O(n^4) O(n4)种情况的所有答案。

朴素的想法是把一个状态表示为 ( x 1 , y 1 , x 2 , y 2 , 0 / 1 ) (x_1,y_1,x_2,y_2,0/1) (x1,y1,x2,y2,0/1),表示两个棋子的位置以及当前该谁走。

容易注意到转移是带环的,这意味着 S u r r e a l N u m b e r Surreal Number SurrealNumber那套理论用不了了。

直接SPFA迭代即可。

一个可以简化的地方,如果当前状态是先手胜,就表示为 I N F − s t e p INF-step INFstep,如果是后手胜,就表示为 − I N F + s t e p -INF+step INF+step,这样转移就是取一个min/max的事情了。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

class TheEasyChase{
	private:
		static cs int N=22,INF=1e9;
		int n;int f[N][N][N][N][2],vis[N][N][N][N][2];
		struct node{int x1,y1,x2,y2,t;};
		
		void ckmn(int &a,int b){a>b?a=b:0;}
		void ckmx(int &a,int b){a<b?a=b:0;}
		int sign(int a){return a==0?0:(a<0?-1:1);}
		bool check(int x,int y){return 1<=x&&x<=n&&1<=y&&y<=n;}
		bool recalc(int x1,int y1,int x2,int y2,int o){
			if(x1==x2&&y1==y2)return false;
			int tmp=f[x1][y1][x2][y2][o],res=o?INF:-INF;
			if(o==1){
				for(int re i=0;i<8;++i){
					static cs int dx[]={0,1,0,-1,0,2,0,-2};
					static cs int dy[]={1,0,-1,0,2,0,-2,0};
					int nx=x2+dx[i],ny=y2+dy[i];
					if(check(nx,ny)){
						int val=f[x1][y1][nx][ny][0];
						res=std::min(res,val-sign(val));
					}
				}
			}else {
				for(int re i=0;i<4;++i){
					static cs int dx[]={0,1,0,-1};
					static cs int dy[]={1,0,-1,0};
					int nx=x1+dx[i],ny=y1+dy[i];
					if(check(nx,ny)){
						int val=f[nx][ny][x2][y2][1];
						res=std::max(res,val-sign(val));
					}
				}
			}
			f[x1][y1][x2][y2][o]=res;
			return res!=tmp;
		}
		void solve(){
			std::queue<node> q;
			for(int re i=1;i<=n;++i)
			for(int re j=1;j<=n;++j){
				f[i][j][i][j][0]=-INF;
				f[i][j][i][j][1]=INF;
				vis[i][j][i][j][0]=true;
				vis[i][j][i][j][1]=true;
				q.push({i,j,i,j,0});
				q.push({i,j,i,j,1});
			}
			for(int re i=1;i<=n;++i)
			for(int re j=1;j<=n;++j)
			for(int re k=1;k<=n;++k)
			for(int re l=1;l<=n;++l){
				f[i][j][k][l][0]=-INF;
				f[i][j][k][l][1]=INF;
			} 
			while(!q.empty()){
				node t=q.front();q.pop();
				int x1=t.x1,x2=t.x2,y1=t.y1,y2=t.y2,o=t.t;
				vis[x1][y1][x2][y2][o]=false;
				if(o==1){
					for(int re i=0;i<4;++i){
						static cs int dx[]={0,1,0,-1};
						static cs int dy[]={1,0,-1,0};
						int nx=x1+dx[i],ny=y1+dy[i];
						if(check(nx,ny)&&recalc(nx,ny,x2,y2,0)){
							if(!vis[nx][ny][x2][y2][0]){
								vis[nx][ny][x2][y2][0]=true;
								q.push({nx,ny,x2,y2,0});
							}
						}
					}
				}else {
					for(int re i=0;i<8;++i){
						static cs int dx[]={0,1,0,-1,0,2,0,-2};
						static cs int dy[]={1,0,-1,0,2,0,-2,0};
						int nx=x2+dx[i],ny=y2+dy[i];
						if(check(nx,ny)&&recalc(x1,y1,nx,ny,1)){
							if(!vis[x1][y1][nx][ny][1]){
								vis[x1][y1][nx][ny][1]=true;
								q.push({x1,y1,nx,ny,1});
							}
						}
					}
				}
			}
		}
		
		std::string to_str(int a){
			assert(a>=0);
			char ch[23]={};int l=0;
			do{ch[l++]=(a%10)^48,a/=10;}while(a);
			std::reverse(ch,ch+l);
			return std::string(ch,ch+l);
		}
	public:
		TheEasyChase(){}
		std::string winner(int _n,int rowWhite,int colWhite,
			int rowBlack,int colBlack){
			n=_n;solve();std::string s;
			int val=f[rowWhite][colWhite][rowBlack][colBlack][0];
			if(val>0){
				s="WHITE ";
				val=INF-val;
				s=s+to_str(val);
			}else {
				s="BLACK ";
				val=val+INF;
				s=s+to_str(val);
			}return s;
		}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值