Appearance
Functional Graph
各頂点から出る有向辺がちょうど1本のグラフ。
特徴
各頂点の遷移先を nxt[v] で管理できる。
cpp
vector<int> nxt(n);例えば、次のようなグラフ。
text
0 → 1 → 2 → 3 → 4
↑ ↑ |
5 └───────┘このグラフでは 2 → 3 → 4 → 2 がサイクルになっている。
重要な性質
- 各頂点の出次数は必ず1。
- 各弱連結成分には、有向サイクルがちょうど1つ存在する。
- サイクル以外の頂点は、最終的にそのサイクルに到達する。
- 自己ループも長さ1のサイクルとして扱う。
- 頂点数Nなら、辺数もN。
つまり、各連結成分は 1つのサイクルと、そこに向かって伸びる木 から構成される。
典型的な解法
| やりたいこと | 解法 |
|---|---|
| サイクルを見つける | 訪問状態を管理して辿る |
| サイクル上の頂点を列挙 | 入次数0の頂点を削除 |
| K回遷移した先を求める | ダブリング |
| サイクルまでの距離 | トポロジカルな削除順を逆に処理 |
| 強連結成分に分解する | SCC |
サイクル上の頂点を求める
入次数0の頂点を順番に削除すると、最後にサイクル上の頂点だけが残る。
cpp
vector<int> indeg(n);
for (int v = 0; v < n; v++) indeg[nxt[v]]++;
queue<int> q;
for (int v = 0; v < n; v++) {
if (indeg[v] == 0) q.push(v);
}
while (!q.empty()) {
int v = q.front(); q.pop();
int nv = nxt[v];
if (--indeg[nv] == 0) q.push(nv);
}
// indeg[v] > 0 ならサイクル上の頂点計算量:O(N)
K回遷移した先を求める
nxt[v] を繰り返し適用する。
Kが大きい場合は、ダブリングで高速化できる。
- 前処理:O(N log K)
- クエリ:O(log K)
注意点
- 一般の有向グラフと異なり、各頂点の出次数はちょうど1。
- 各弱連結成分にサイクルは必ず1つ存在する。
- 自己ループもサイクルに含まれる。
- 非連結な場合、サイクルは複数存在することがある。
- サイクル上の頂点以外は、削除順を逆に処理すると距離などをDPできる。