传送门
题解:
注意到状态数其实不是很多,也就是说我们可以想办法按照某种顺序处理出所有 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 INF−step,如果是后手胜,就表示为 − 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;
}
};