TopCoder SRM 385 Div1 Medium TurningMaze
問題
hxwのマスで表される迷路がある。
それぞれのマスは
- 'A'は壁が四方にないこと
- 'B'は壁が四方全部にあること
- 'C'は壁が左右方向にだけあること
- 'D'は壁が上下方向にだけあること
を意味する。
左上のマスを出発して、右下のマスまで辿り着きたい。
1ターンに、壁のない方向のマスに移動するか、次の回転操作のどちらかを行うことができる。
右下のマスに辿り着くのに必票な時間の最小値を求めよ。
右下のマスにどうやっても辿り着くことが出来ない場合、-1を返せ。
ただし、グリッドの外にはみでてはならないものとする。
回転操作:
自分のいる列のマスを全て時計回りに回転させ、自分のいる行のマスを全て時計周りに回転させる。
制約条件
行,列≦7
方針
自明に無理だったら(C,Dのマスをのマスとみなしても右下のマスに辿り着けない)
その時点で-1を返す。
無理じゃなかったら、A*探索をする。
ゴールまでの距離の推定値はマンハッタン距離を使った。
また、A,Bのマスは回転させても意味がないので、状態に含めないようにする。
これで通ってしまった。
editorialでの解法は、
反転状態は、行と列のうち反転しているものの集合により一意に決まるので、
2^14個の状態を持つようにするというものだった。
なので、状態数は2^14*7*7個しかないっぽい。
これだったら何も考えないA*書いて通るのも納得。
ソースコード
const int dy[]={-1,0,1,0},dx[]={0,-1,0,1}; vs M; int h,w; bool ck(){ queue<int> q; bool v[50][50]={}; q.push(0); while(!q.empty()){ int y=q.front()/w, x=q.front()%w; q.pop(); v[y][x]=1; if(y==h-1&&x==w-1)return 1; rep(d,4){ int ny=y+dy[d], nx=x+dx[d]; if(ny<0||ny>=h||nx<0||nx>=w||v[ny][nx])continue; if(M[ny][nx]=='B')continue; q.push(ny*w+nx); } } return 0; } class TurningMaze { public: int minTime(vector <string> maze) { h=maze.size(); w=maze[0].size(); M=maze; if(!ck())return -1; typedef pair<pi,pi> P; //guess, time, state, pos #define D(y,x) (h-y-1+w-x-1) priority_queue<P,vector<P>,greater<P> > q; set<pi> v; q.push(mp(mp(D(0,0),0),mp(0,0))); while(!q.empty()){ int y=q.top().second.second/w,x=q.top().second.second%w; ll state=q.top().second.first; int t=q.top().first.second; q.pop(); if(v.count(mp(state,y*w+x)))continue; v.insert(mp(state,y*w+x)); if(y==h-1&&x==w-1)return t; rep(d,4){ int ny=y+dy[d], nx=x+dx[d]; if(ny<0||nx<0||ny>=h||nx>=w||v.count(mp(state,ny*w+nx))) continue; int cdir=M[y][x]-'C'^state>>y*w+x&1; int ndir=M[ny][nx]-'C'^state>>ny*w+nx&1; if(M[ny][nx]=='B'||M[y][x]!='A'&&cdir!=d%2|| M[ny][nx]!='A'&&ndir!=d%2)continue; q.push(mp(mp(D(ny,nx)+t+1,t+1),mp(state,ny*w+nx))); } rep(i,h)if(M[i][x]=='C'||M[i][x]=='D')state^=1ll<<i*w+x; rep(i,w)if(M[y][i]=='C'||M[y][i]=='D')state^=1ll<<y*w+i; if(!v.count(mp(state,y*w+x))) q.push(mp(mp(D(y,x)+t+1,t+1),mp(state,y*w+x))); } return -1; } };