acl_cpp.scc
scc.scc_graph
# scc_graph
from acl_cpp.scc import scc_graph
有向グラフを強連結成分分解します。
コンストラクタ
# scc_graph::scc_graph(int n)
def scc_graph(n: int = 0) -> scc_graph
\(n\) 頂点 \(0\) 辺のグラフを作成します。
制約
\(0 \le n < 2^{31}\)
計算量
\(O(n)\)
scc_graph.add_edge
# void scc_graph::add_edge(int from, int to)
def scc_graph.add_edge(from_: int, to: int) -> None
頂点 \(\mathit{from\_}\) から頂点 \(\mathit{to}\) への辺を追加します。
制約
\(0 \le \mathit{from\_} < n\)
\(0 \le \mathit{to} < n\)
計算量
ならし \(O(1)\)
scc_graph.scc
# vector<vector<int>> scc_graph::scc()
def scc_graph.scc() -> list[list[int]]
以下の条件を満たすような、「頂点のリスト」のリストを返します。
全ての頂点がちょうど 1 つずつ、どれかのリストに含まれます。
内側のリストと強連結成分が一対一に対応します。リスト内での頂点の順序は未定義です。
リストはトポロジカルソートされています。異なる強連結成分の頂点 \(u, v\) について、\(u\) から \(v\) に到達できる時、\(u\) の属するリストは \(v\) の属するリストよりも前です。
計算量
追加した辺の本数を \(m\) として
\(O(n + m)\)
使用例
AC code of https://atcoder.jp/contests/practice2/tasks/practice2_g
from acl_cpp.scc import scc_graph
N, M = map(int, input().split())
g = scc_graph(N)
for _ in range(M):
u, v = map(int, input().split())
g.add_edge(u, v)
scc = g.scc()
print(len(scc))
for component in scc:
print(len(component), *component)