あるグラフに n 個の頂点と e 個の辺が与えられたときに、任意の頂点から始めて、その頂点から到達可能な頂点を段階的にすべて訪問したいと考えてみましょう。実現方法はいろいろありますが、その中でも特によく使われるのが幅優先探索 (BFS) アルゴリズムです。BFS の特徴として、始点から各頂点への最短経路が簡単に求められることが挙げられ、さまざまな応用分野で重宝されます。
from collections import deque
n, e = map(int, input().split()) # n: 頂点数, e: 辺の数
g = [[] for _ in range(n)] # グラフ - 隣接リスト
for _ in range(e): # 辺を読み込む
a, b = map(int, input().split()) # a -> b および b -> a
g[a].append(b)
g[b].append(a)
start = int(input()) # 開始頂点
used = [False] * n # 使用済み(訪問済み)の頂点
q = deque([start]) # 頂点のキュー
used[start] = True # 開始頂点を訪問済みにする
while q: # キューが空でない間
v = q.popleft() # キューから頂点を取り出す
print(v, end=' ') # 頂点を出力する
for to in g[v]: # v とつながっている各頂点について
if not used[to]: # もし未訪問の頂点なら
q.append(to) # 頂点をキューに追加する
used[to] = True # 頂点を訪問済みにする
まず、グラフの初期化をして start 頂点から探索を開始します。最初は used のすべてを False としておきますが、訪問する頂点が決まったら、キューに追加して used を更新していきます。これが「グラフが燃える」イメージに対応しています。各ステップでは、現在の頂点 v に隣接していて、まだ訪問していない頂点をすべてキューに入れ、訪問済みに設定する、という操作を繰り返します。
以下の入力例でアルゴリズムをシミュレーションしてみましょう。
n = 4, e = 4
The input a, b pairs are the following: [(0, 1), (0, 2), (1, 2), (3, 2)]
The starting vertex is 3
used = [False, False, False, True], q = [3]
v = 3, q = [] → add all the neighbors that are not used to the queue
used = [False, False, True, True], q = [2]
v = 2, q = [] → add all the neighbors that are not used to the queue
used = [True, True, True, True], q = [0, 1]
v = 0, q = [1] → add all the neighbors that are not used to the queue
v = 1, q = [] → add all the neighbors that are not used to the queue
Done
n = 5, e = 4
The input a, b pairs are the following: [(0, 1), (0, 2), (1, 2), (3, 4)]
The starting vertex is 0
used = [True, False, False, False, False], q = [0]
v = 0, q = [] → add all the neighbors that are not used to the queue