AOJ 2017 Karakuri Doll
制約条件
H≦16
W≦50
部屋の最も外側のマスは壁である。
方針
まずは、スタートからゴールへ行けるかだけを探索する。
これは、普通にロボットの動きをシミュレートする幅優先探索をすればいい。
次に、ゴールへ行きつつ、逆実行するとゴールからスタートへ戻れるプログラムがあるかを探索する。
これは、スタートからゴールへ順実行で行く経路と、
ゴールからスタートへ戻る経路を逆から、すなわちスタートから後ろ向きにゴールへ行く経路を同時に探索すればいい。
帰りの探索では、壁のほうを向けるマスが、次にキューに入れるマスである。
ソースコード
const int dy[] = {-1, 0, 1, 0}, dx[] = {0, -1, 0, 1}; int h, w, sy, sx, sd, gd; string in[16]; bool solve(){ static bool v[16][64][4]; memset(v, 0, sizeof(v)); queue<pi> q; q.push(mp(sy * w + sx, sd)); v[sy][sx][sd] = 1; while(!q.empty()){ int y = q.front().first / w, x = q.front().first % w; int dir = q.front().second; q.pop(); while(in[y+dy[dir]][x+dx[dir]] !='#') y += dy[dir], x += dx[dir]; if(in[y][x] == 'M') return 1; dir = dir + 1 & 3; rep(d, 2){ if(!v[y][x][dir]){ v[y][x][dir] = 1; q.push(mp(y * w + x, dir)); } dir = dir + 2 & 3; } } return 0; } bool solve2(){ set<pair<pi, pi> > s; queue<pair<pi, pi> > q; rep(d, 4){ q.push(mp(mp(sy * w + sx, sd), mp(sy * w + sx, d))); s.insert(mp(mp(sy * w + sx, sd), mp(sy * w + sx, d))); } while(!q.empty()){ int y1, x1, d1, y2, x2, d2; y1 = q.front().first.first / w, x1 = q.front().first.first % w; y2 = q.front().second.first / w, x2 = q.front().second.first % w; d1 = q.front().first.second, d2 = q.front().second.second; q.pop(); while(in[y1 + dy[d1]][x1 + dx[d1]] != '#') y1 += dy[d1], x1 += dx[d1]; while(1){ for(int i = 1; i < 5; i += 2){ int nd1 = d1 + i & 3, nd2 = d2 + i & 3; if(in[y2 + dy[nd2]][x2 + dx[nd2]] == '#'){ if(!s.count(mp(mp(y1 * w + x1, nd1), mp(y2 * w + x2, nd2)))){ s.insert(mp(mp(y1 * w + x1, nd1), mp(y2 * w + x2, nd2))); q.push(mp(mp(y1 * w + x1, nd1), mp(y2 * w + x2, nd2))); } } } if(in[y2 - dy[d2]][x2 - dx[d2]] == '#') break; y2 -= dy[d2], x2 -= dx[d2]; } if(in[y1][x1] == 'M' && in[y2][x2] == 'M' && d2 == gd) return 1; } return 0; } int main() { while(cin >> w >> h, w){ rep(i, h) cin >> in[i]; rep(i, h) rep(j, w){ if(in[i][j] == 'K'){ sy = i, sx = j; rep(d, 4){ int ny = i + dy[d], nx = j + dx[d]; if(in[ny][nx] != '#') sd = d; } } if(in[i][j] == 'M'){ rep(d, 4){ int ny = i + dy[d], nx = j + dx[d]; if(in[ny][nx] != '#') gd = d; } } } bool iki = solve(), kaeri = solve2(); if(iki && kaeri) puts("He can accomplish his mission."); else if(iki) puts("He cannot return to the kitchen."); else puts("He cannot bring tea to his master."); } return 0; }