TopCoder SRM 423 Div1 Medium TheEasyChase
問題
nxnのチェス盤と二つの駒を使って二人が次のようなゲームをする。
- 最初先手の駒は(y1,x1)の位置に、後手の駒は(y2,x2)の位置におかれている。
- 二人は交互に、駒を上下左右の好きな方向へ、先手は1歩、後手は1歩または2歩動かす。
- 相手の駒を取ったプレイヤーの勝ち。
- お互いのプレイヤーは最善をつくす(勝てるなら最短手数で勝つことをめざし、負けるときはなるべく長い手数で負けることを目指す)
nおよびy1,x1,y2,x2が与えられるとき、
お互いが最善を尽くすとしてどちらが何手目で勝つかを求めよ。
制約条件
n≦20
方針
先手が一手で勝てる場合を除き必ず後手必勝になるクソゲーである。
ゲームの探索であるが、無限ループに入る可能性があることが普通と少し違う。
勝ち負けの確定した状態のノードはわかっているので、
そこからベルマンフォードっぽく勝ち負けを確定させていく。
遷移の仕方は普通のゲーム木の探索と同じで、先手負けに遷移できるならば先手の勝ち、
先手の勝ちにしか遷移できないなら先手の負け。
まだ不明な場合は不明にしておく。
ソースコード
const int dy[]={-1,0,1,0,-2,0,2,0},dx[]={0,-1,0,1,0,-2,0,2}; int dp[2][400][400]; class TheEasyChase { public: string winner(int n, int y1, int x1, int y2, int x2) { rep(k,2)rep(i,400)rep(j,400)dp[k][i][j]=-inf; rep(k,2)rep(i,n)rep(j,n)dp[k][i*n+j][i*n+j]=0; for(;;){ bool update=0; rep(p,2)rep(i,n)rep(j,n)rep(k,n)rep(l,n) if(dp[p][i*n+j][k*n+l]==-inf){ bool unknown=0; int ans=inf; rep(d,(p?8:4)){ int ny=i+dy[d], nx=j+dx[d], np=1-p; if(ny<0||nx<0||ny>=n||nx>=n)continue; int next=dp[np][k*n+l][ny*n+nx]; if(next==-inf)unknown=1; else{ if(ans==inf||ans<0&&next<=0)ans=-next; else if(ans>=0&&next<=0)ans=min(ans,-next); else if(ans<0)ans=min(ans,-next); } } if(ans!=inf&&ans>=0){ dp[p][i*n+j][k*n+l]=ans+1; update=1; } else if(!unknown){ dp[p][i*n+j][k*n+l]=ans-1; update=1; } } if(!update)break; } y1--; x1--; y2--; x2--; stringstream ss; ss<<(dp[0][y1*n+x1][y2*n+x2]>0?"WHITE":"BLACK") <<" "<<abs(dp[0][y1*n+x1][y2*n+x2]); return ss.str(); } };