C - うわさの伝播 / Spread of Rumors 解説 by admin
GPT 5.4 High概要
人を頂点、連絡手段を有向辺とみなすと、この問題は「始点 \(S\) から各頂点への最短距離」を求める問題です。
各人がうわさを知る最も早い日は \(S\) からその人までの最短辺数に等しいので、全員に届くなら答えはその最大値、届かない人がいれば \(-1\) です。
考察
うわさは、ある日に知っている人から翌日に隣の人へ伝わります。
つまり、
- 1 日で進めるのはちょうど 1 本の辺
- ある人に最初に届く日は、\(S\) からその人までの「最小の辺数」
となります。
たとえば
- \(S \to A\)
- \(A \to B\)
- \(S \to C\)
という辺があるなら、
- \(S\) は日 \(0\)
- \(A, C\) は日 \(1\)
- \(B\) は日 \(2\)
に知ることになります。
これはまさに、始点 \(S\) からの最短距離そのものです。
重要な気づき
この問題では辺に重みがなく、どの連絡手段も「1 日」で届きます。
したがって、必要なのは 重みなし有向グラフの最短距離 であり、これは BFS(幅優先探索) で求められます。
素朴な方法が厳しい理由
「日ごとに、今知っている人全員から次に広がる人をシミュレーションする」こと自体は考え方としては正しいです。
しかし、実装によっては毎日全頂点や全辺を何度も見てしまい、最悪で非常に遅くなります。
また、DFS(深さ優先探索)では「最初に見つけた経路」が最短とは限らないため、各人が知る最も早い日を正しく求めるのには向きません。
どう解決するか
BFS は「距離 \(0\) の頂点 → 距離 \(1\) の頂点 → 距離 \(2\) の頂点 …」の順に探索します。
そのため、各頂点に最初に到達したときの距離が、その頂点への最短距離になります。
この最短距離を dist[i] とすると、
dist[i] = -1ならその人には永遠に届かない- 全員に届くなら、全員が知る最初の日は \(\max_i dist[i]\)
です。
アルゴリズム
- 人を頂点、連絡手段を有向辺とした隣接リストを作る。
- 配列
distを-1で初期化する。 - 始点
Sについてdist[S] = 0とし、キューに入れる。 - BFS を行う。
- キューから頂点
uを取り出す uから行ける各頂点vについて、まだ未訪問ならdist[v] = dist[u] + 1- キューに追加
- キューから頂点
- BFS 終了後、
dist[i] = -1の人が 1 人でもいれば-1- そうでなければ
distの最大値を出力
なぜこれで正しいか
- うわさは 1 日ごとに 1 本の辺だけ進むので、ある人に届く最短日数は最短辺数です。
- BFS は辺数の少ない順に探索するので、
dist[i]は \(S\) から \(i\) への最短辺数になります。 - 全員が知る日は、最後の 1 人に届く日です。したがって答えは最短距離の最大値です。
- 到達できない人がいれば、いつまで経っても全員には広まりません。
計算量
- 時間計算量: \(O(N + M)\)
- 空間計算量: \(O(N + M)\)
実装のポイント
グラフは 有向グラフ なので、
u -> vの向きだけを追加します。最短距離を求めるので、キューを使った BFS を用います。
distを-1で初期化しておくと、- 未到達かどうかの判定
- 到達日数の記録
を 1 つの配列で兼ねられて便利です。
最後に
distを見て、未到達の人がいれば即座に-1を出力できます。ソースコード
import sys
from collections import deque
def main():
input = sys.stdin.readline
N, M, S = map(int, input().split())
graph = [[] for _ in range(N + 1)]
for _ in range(M):
u, v = map(int, input().split())
graph[u].append(v)
dist = [-1] * (N + 1)
dist[S] = 0
q = deque([S])
while q:
u = q.popleft()
du = dist[u]
for v in graph[u]:
if dist[v] == -1:
dist[v] = du + 1
q.append(v)
ans = 0
for i in range(1, N + 1):
if dist[i] == -1:
print(-1)
return
if dist[i] > ans:
ans = dist[i]
print(ans)
if __name__ == "__main__":
main()
この解説は gpt-5.4-high によって生成されました。
投稿日時:
最終更新: