PythonでAizu Online Judgeを解く/GRL_4_B - Topological Sort
Posted on
概要
DAG であるグラフ \(G (V, E)\) について頂点をトポロジカル順序で出力してください。
入力
%python def input(f): V, E = map(int, f.readline().split()) s = [None for _ in range(E)] t = [None for _ in range(E)] for i in range(E): s[i], t[i] = map(int, f.readline().split()) return V, E, s, t
制約
- \(1 \leq |V| \leq 10,000\)
- \(0 \leq |E| \leq 100,000\)
- \(G\) は平行辺を持たない
- \(G\) は自己ループを持たない
サンプル入力
%sh cat <<EOF > /tmp/input1.txt 6 6 0 1 1 2 3 1 3 4 4 5 5 2 EOF
%python with open('/tmp/input1.txt') as f: print(input(f))
(6, 6, [0, 1, 3, 3, 4, 5], [1, 2, 1, 4, 5, 2])
考え方
トポロジカル順序は頂点間の依存関係を元にしたものでパッケージ管理などで活用することができます。計算については強連結成分分解と同様に各頂点について深さ優先探索で訪れた順に頂点をリストに追加していくことにより \(\mathcal{O}(V+E)\) 程度の計算量に収まります。
実装例
%python def solve(V, E, s, t): graph = [[] for _ in range(V)] def add_edge(src, dst): graph[src].append(dst) for i in range(E): add_edge(s[i], t[i]) order = [] used = [False for _ in range(V)] def rec(cur, prev): used[cur] = True for nxt in graph[cur]: if not used[nxt]: rec(nxt, cur) order.append(cur) for i in range(V): if not used[i]: rec(i, -1) return order def output(order): for v in reversed(order): print(v)
サンプル出力
%python with open('/tmp/input1.txt') as f: output(solve(*input(f)))
3 4 5 0 1 2
トポロジカルソートの可視化
%sh curl -s https://judgedat.u-aizu.ac.jp/testcases/GRL_4_B/15/in > /tmp/input15.txt head /tmp/input15.txt
20 42 4 19 4 10 4 7 6 2 6 8 6 14 11 12 11 9 11 0
%python with open('/tmp/input15.txt') as f: output(solve(*input(f)))
17 13 11 12 6 14 8 4 2 9 16 5 19 0 10 15 1 18 7 3
良い感じの見せ方が思いつきませんでした :-|