Official

C - 避難経路 / Evacuation Route Editorial by MtSaka


部屋を頂点、廊下を辺に対応させたグラフを考えます。このグラフにおいて、火災が発生している部屋に対応する頂点を通らずに頂点 \(T\) に到達できる頂点が脱落することなく部屋 \(T\) に到達できる部屋です。また、各部屋にいる避難者に必要なターン数は頂点 \(T\) からの火災が発生している部屋に対応する頂点を通らない最短距離です。この最短距離が求まればよいです。もし到達できないならばこの最短距離が無限大となるようにします。こうすることで避難者がいるどれか一つの部屋の最短距離が無限大となる場合に全員は避難できず、逆に全てが無限大でないならば避難者の部屋についての最短距離の最大値が答えとなります。

最短距離を求める方法を考えます。火災が発生している部屋に対応する頂点をすべて無効な頂点とし、これらを結ぶ辺がすべてないものとすることで一般のグラフにおける単一始点最短経路となります。これは幅優先探索(BFS)などで時間計算量 \(\mathrm{O}(N+M)\) で計算できます。最短経路を求めた後は上で説明した通りに全員が避難できるか判定し、最短距離の最大値を求めればよいです。

実装例(C++)

#include <bits/stdc++.h>
using namespace std;
int main() {
    int n, m, k, q, t;
    cin >> n >> m >> k >> q >> t;
    t--;
    vector<vector<int>> g(n);
    for (int i = 0; i < m; ++i) {
        int u, v;
        cin >> u >> v;
        u--, v--;
        g[u].emplace_back(v);
        g[v].emplace_back(u);
    }
    vector<int> s(k);
    for (auto& e : s) cin >> e;
    for (auto& e : s) e--;
    vector<int> p(q);
    for (auto& e : p) cin >> e;
    for (auto& e : p) e--;
    vector<int> fire(n, 0);
    for (auto& e : p) fire[e] = 1;
    queue<int> que;
    que.emplace(t);
    vector<int> dist(n, 1e9);
    dist[t] = 0;
    while (!que.empty()) {
        int v = que.front();
        que.pop();
        for (auto u : g[v]) {
            if (fire[u]) continue;
            if (dist[u] > dist[v] + 1) {
                dist[u] = dist[v] + 1;
                que.emplace(u);
            }
        }
    }
    int res = 0;
    for (auto& e : s) {
        if (dist[e] == (int)1e9) {
            cout << -1 << endl;
            return 0;
        }
        res = max(res, dist[e]);
    }
    cout << res << endl;
}

posted:
last update: