AGC033 A - Darker and Darker
目次
# 問題
https://atcoder.jp/contests/agc033/tasks/agc033_a
# 入力
...
.
- - ボードの高さと幅
- - マス.
.
は白#
は黒
# 出力
1回の操作で#
の上下左右4マスを#
に更新することが出来る.
最小で何回の操作ですべてのマスを#
にすることが出来るか.
# 解説
最短手数を求める問題なので幅優先探索が相性が良さそうです.
一番最初に#
であるマスの距離をとします.
そこから1回操作を行うごとに#
に変わっていくマスの距離をしていきます.
するとそのマスが何回目の操作で#
に変わったのかが分かります.
そして一番最初に全マスが#
に変わった瞬間に、そのマスの距離がそのまま答えになります.
幅優先探索では最初に見つかったものが最短距離であることが保証されているからです.
全マスが#
に変わったかどうかは、カウンタを用意し#
に変えるたびに数えていきます.
そしてマスの個数はなのでそれと等しくなったら全マス#
になったと判定出来ます.
# 計算量
すべてのマスについて1回ずつ訪問します.
# 解答
#define MAX_H 1000
#define INFTY (MAX_H*MAX_H)
Int H, W;
char c_;
vector<bool> M(MAX_H * MAX_H, false);
vector<Int> dist(MAX_H * MAX_H, INFTY);
vector<Vector2> starts;
Int at(Int x, Int y) {
return y*W+x;
}
Int at(Vector2 &v) {
return v.y*W+v.x;
}
bool valid(Vector2 &v) {
if (v.x < 0 || v.x >= W || v.y < 0 || v.y >= H) return false;
if (dist.at(at(v)) < INFTY) return false;
return true;
}
void input() {
cin >> H >> W;
loop(h,0,H) {
loop(w,0,W) {
cin >> c_;
if (c_ == '#') {
M[at(w, h)] = true;
starts.push_back(Vector2(w, h));
}
}
}
M.resize(H * W);
dist.resize(H * W);
}
// Up Down Left Right
vector<Vector2> udlr = { {0, 1}, {0, -1}, {-1, 0}, {1, 0} };
Int bfs() {
Int counter = starts.size();
if (counter >= H*W) return 0;
queue<Vector2> Q;
for (auto s: starts) {
Q.push(s);
dist[at(s)] = 0;
}
while (Q.size()) {
Vector2 u = Q.front(); Q.pop();
for (auto dxdy: udlr) {
Vector2 next = u + dxdy;
if (!valid(next)) continue;
dist[at(next)] = dist.at(at(u)) + 1;
counter++;
if (counter >= H*W) {
return dist.at(at(next));
}
Q.push(next);
}
}
return -1;
}
void solve() {
cout << bfs() << endl;
}
int main(void) {
input();
solve();
return 0;
}