B - 噂の広がり / Spread of Rumors 解説 by admin
Claude 4.6 Opus (Thinking)概要
噂を知っている生徒がグループワークのペアを通じて順番に噂を広めていく様子をシミュレーションし、最終的に噂を知っている生徒の人数を求める問題です。
考察
重要な気づき
この問題のポイントはグループワークが順番通りに行われるという点です。噂の伝播は時系列に依存します。
例えば、以下のケースを考えましょう:
- \(N = 4, M = 2, K = 1\)(生徒1が最初に噂を知っている)
- グループワーク1: 生徒2と生徒3がペア
- グループワーク2: 生徒1と生徒2がペア
この場合: 1. グループワーク1の時点では、生徒2も生徒3も噂を知らないので、何も起きません。 2. グループワーク2で、生徒1(噂を知っている)と生徒2がペアになるので、生徒2が噂を知ります。
最終的に噂を知っているのは生徒1と生徒2の 2人 です。もし順番が逆なら結果は変わります。このように、順番を無視してはいけないことが重要です。
アプローチ
グループワークの回数 \(M\) が最大 \(2 \times 10^5\) と十分小さいため、各グループワークを1つずつ順番にシミュレーションするだけで十分間に合います。
各グループワークでは、ペアのどちらか一方でも噂を知っていれば、両方が噂を知っている状態に更新します。
アルゴリズム
- 長さ \(N+1\) の配列
knowsを用意し、出席番号 \(1\) から \(K\) までの生徒をTrue(噂を知っている)に初期化する。 - \(M\) 回のグループワークを順番に処理する:
- ペア \((A_i, B_i)\) を読み取る。
knows[A_i]またはknows[B_i]のいずれかがTrueなら、両方をTrueにする。
- 最後に
knows配列中のTrueの個数を数えて出力する。
具体例(\(N=5, M=3, K=2\)、つまり生徒1,2が最初に噂を知っている場合):
| グループワーク | ペア | 噂を知っている生徒 |
|---|---|---|
| 初期状態 | - | {1, 2} |
| 1回目 | (2, 4) | {1, 2, 4}(生徒2が知っているので生徒4に伝わる) |
| 2回目 | (3, 5) | {1, 2, 4}(どちらも知らないので変化なし) |
| 3回目 | (4, 5) | {1, 2, 4, 5}(生徒4が知っているので生徒5に伝わる) |
答え: 4
計算量
- 時間計算量: \(O(N + M)\)
- 初期化に \(O(N)\)、各グループワークの処理に \(O(1)\) で合計 \(O(M)\)、最後の集計に \(O(N)\)
- 空間計算量: \(O(N)\)
knows配列の分
実装のポイント
生徒の出席番号が \(1\) から始まるため、配列を \(N+1\) の大きさで確保して 1-indexed でアクセスすると実装が楽です。
knows配列をbool型で管理し、sum(knows)でTrueの個数を数えられます(Python ではTrueは1、Falseは0として加算されます)。グループワークの順序が結果に影響するため、必ず入力された順番通りに処理する必要があります。
ソースコード
import sys
input = sys.stdin.readline
def main():
N, M, K = map(int, input().split())
# knows[i] = True if student i knows the rumor
knows = [False] * (N + 1)
for i in range(1, K + 1):
knows[i] = True
for _ in range(M):
a, b = map(int, input().split())
if knows[a] or knows[b]:
knows[a] = True
knows[b] = True
print(sum(knows))
main()
この解説は claude4.6opus-thinking によって生成されました。
投稿日時:
最終更新: