JOI2011予選 E - チーズ
目次
# 問題
https://atcoder.jp/contests/joi2011yo/tasks/joi2011yo_e
# 入力
# 出力
# 解説
まず最短経路を求める問題なので幅優先探索が使えそうです.
ただしゴールが明示されておらず、すべてのチーズを食べることが終了条件です.
問題文が長く混乱しやすいですが、注意深く状況を整理すると、実はチーズに順番があり、次のチーズをゴールとしてチーズの数だけ幅優先探索で移動を繰り返すという問題であることが分かります.
図面はで最大、ゴールの数は最大なのでとなり十分間にあいます.
ゴールが次のチーズに移動するたびに距離の配列を初期化するのを忘れないように注意が必要です.
# 計算量
# 解答
#define MAX_H 1000
#define INFTY (1000*1000)
Int H, W, N, sx, sy;
char c_;
vector<Int> M(MAX_H * MAX_H, 0);
vector<Vector2> goals(9);
void input() {
cin >> H >> W >> N;
loop(h,0,H) {
loop(w,0,W) {
cin >> c_;
if (c_ == 'X') {
M[h*W+w] = -1;
} else if (c_ == 'S') {
sx = w, sy = h;
} else if (1 <= c_ - '0' && c_ - '0' <= 9) {
M[h*W+w] = c_ - '0';
goals[(c_ - '0') - 1] = Vector2(w, h);
}
}
}
goals.resize(N);
}
Int bfs(Int sx, Int sy, Int gx, Int gy) {
queue<Vector2> Q;
vector<Int> dist(MAX_H*MAX_H, INFTY);
Q.push(Vector2(sx, sy));
dist[sy*W+sx] = 0;
while (Q.size()) {
Vector2 u = Q.front(); Q.pop();
loop(dx,-1,2) {
loop(dy,-1,2) {
if (dx != 0 && dy != 0) continue;
Vector2 next = u + Vector2(dx, dy);
if (next.x < 0 || next.x >= W || next.y < 0 || next.y >= H) continue;
if (M.at(next.y*W+next.x) < 0) continue;
if (dist.at(next.y*W+next.x) < INFTY) continue;
dist[next.y*W+next.x] = dist[u.y*W+u.x] + 1;
if (next.x == gx && next.y == gy) {
return dist[next.y*W+next.x];
}
Q.push(next);
}
}
}
return INFTY;
}
void solve() {
Int moved = 0;
for (auto goal: goals) {
moved += bfs(sx, sy, goal.x, goal.y);
sx = goal.x, sy = goal.y;
}
cout << moved << endl;
}
int main(void) {
input();
solve();
return 0;
}