TopCoder SRM 266 Div1 Hard AntiChess
問題
以下のような自殺チェスを考える。
- 最初、白は盤上にn個のポーンをもち、それぞれの座標が与えられる
- 黒は1つのクイーンを持ち、その座標が与えられる
- 最初は白の手番
- プレイヤーは取れる駒があったら必ず駒を取らなければならない。複数の駒を取れるときはどれをとってもよい
- 黒が駒を取れなくなったり、合法手がなくなったり、駒がなくなったりしたら終了
- ポーンは前1マスに進める。ただし2列目にいるときは2マス進める
- ポーンが駒を取るときには、斜め前に1マス進む
黒は取られるポーンの数が最大になるように、
白は取るポーンの数が最小になるように手を選ぶものとするとき、
いくつのポーンが取られるか、求めよ。
制約条件
ポーンの数≦8
方針
メモ化して通常のゲーム木探索をすればよい。
ソースコード
const int dy[]={-1,0,1,0,1,1,-1,-1},dx[]={0,-1,0,1,1,-1,1,-1}; map<pi,int> dp; int rec(ll board,int qq,int turn){ int q=qq*2+turn; if(dp.count(mp(board,q)))return dp[mp(board,q)]; if(!turn){ rep(i,8)rep(j,7)if(board&1ll<<i*8+j) if(i+1==qq/8&&j+1==qq%8||i-1==qq/8&&j+1==qq%8)return dp[mp(board,q)]=0; int res=0; rep(i,8)rep(j,7)if((board&1ll<<i*8+j)&&!(board&1ll<<i*8+j+1)&&!(i*8+j+1==qq)){ ll next=board^(1ll<<i*8+j)|(1ll<<i*8+j+1); res=max(res,rec(next,qq,1-turn)); if(j==1&&!(board&1ll<<i*8+j+2)&&!(i*8+j+2==qq)){ ll next=board^(1ll<<i*8+j)|(1ll<<i*8+j+2); res=max(res,rec(next,qq,1-turn)); } } return dp[mp(board,q)]=res; } int x=qq/8, y=qq%8, res=inf; rep(d,8){ int ny=y, nx=x; for(;;){ ny+=dy[d]; nx+=dx[d]; if(ny<0||nx<0||ny>=8||nx>=8)break; if(board&1ll<<nx*8+ny){ ll next=board^1ll<<nx*8+ny; res=min(res,1+rec(next,nx*8+ny,1-turn)); break; } } } if(res==inf)res=0; return dp[mp(board,q)]=res; } class AntiChess { public: int sacrifice(vector <string> white, string black) { ll board=0; rep(i,white.size()){ int a=white[i][0]-'a', b=white[i][1]-'1'; board|=1ll<<a*8+b; } dp.clear(); return rec(board,(black[0]-'a')*8+black[1]-'1',0); } };