深さ優先探索1回で強連結成分分解 C++
コンテンツ
前回の続き.
今回は強連結成分分解する.
しかも,DFS1回だけ実行.
アルゴリズムは非常にシンプル.そして,結構分かりやすいと思うのだが.
アルゴリズムの解説等は以下が比較的分かりやすいと思う.
http://www.ics.uci.edu/~eppstein/161/960220.html#sca
void visit(const Graph &g, int *label, stack<Vertex> &s, const Vertex &u, int *num, int *low, int &index); void scc(const Graph &g, int *label) { // label[a] == label[b] ⇔ aとbは同じ連結成分 const int n = g.succ.size(); int index = 0, *num = new int[n], *low = new int[n]; fill_n(label, n, -1); stack<Vertex> s; for (Vertex i = 0; i < n; ++i) if (label[i] == -1) visit(g, label, s, i, num, low, index); } void visit(const Graph &g, int *label, stack<Vertex> &s,const Vertex &u, int *num, int *low, int &index) { s.push(u); low[u] = num[u] = ++index; foreach(Vertex v, g.succ[u]) { if (label[v] != -1) continue; if (num[v] == 0) visit(g, label, s, v, num, low, index); low[u] = min(low[u], low[v]); } if (num[u] == low[u]) { Vertex v; do v = s.top(), s.pop(), label[v] = u; while (v != u); label[u] = u; } }
↑現実
↓理想(関数内関数が使えれば…)
void scc(const Graph &g, int *label) { const int n = g.succ.size(); int index = 0, *num = new int[n], *low = new int[n]; fill_n(label, n, -1); stack<Vertex> s; void visit(const Vertex &u) { s.push(u); low[u] = num[u] = ++index; foreach(Vertex v, g.succ[u]) { if (label[v] != -1) continue; if (num[v] == 0) visit(v); low[u] = min(low[u], low[v]); } if (num[u] == low[u]) { Vertex v; do v = s.top(), s.pop(), label[v] = u; while (v != u); label[u] = u; } } for (Vertex i = 0; i < n; ++i) if (label[i] == -1) visit(i); }
関数内関数を許可すると再帰とか,相互呼び出しとかで大変なのでしょうか.
作成者 Toru Mano
最終更新時刻 2023-01-01 (c70d5a1)