TOP > グラフ 強連結成分分解
強連結成分分解(Strongly-Connected-Components)
説明
強連結成分分解をする。
計算量
- $O(V + E)$
実装例
- StronglyConnectedComponents($g$):= グラフ $g$ で初期化する。
- build($t$):= 強連結成分分解をする。強連結成分の番号はトポロジカル順に昇順にふられる。 $t$ には強連結成分ごとに縮約したグラフが格納される(多重辺が生えるので注意)。
- [$k$] := 頂点 $k$ が属する強連結成分の番号を返す。
template< typename G >
struct StronglyConnectedComponents {
const G &g;
UnWeightedGraph gg, rg;
vector< int > comp, order, used;
StronglyConnectedComponents(G &g) : g(g), gg(g.size()), rg(g.size()), comp(g.size(), -1), used(g.size()) {
for(int i = 0; i < g.size(); i++) {
for(auto e : g[i]) {
gg[i].emplace_back((int) e);
rg[(int) e].emplace_back(i);
}
}
}
int operator[](int k) {
return comp[k];
}
void dfs(int idx) {
if(used[idx]) return;
used[idx] = true;
for(int to : gg[idx]) dfs(to);
order.push_back(idx);
}
void rdfs(int idx, int cnt) {
if(comp[idx] != -1) return;
comp[idx] = cnt;
for(int to : rg[idx]) rdfs(to, cnt);
}
void build(UnWeightedGraph &t) {
for(int i = 0; i < gg.size(); i++) dfs(i);
reverse(begin(order), end(order));
int ptr = 0;
for(int i : order) if(comp[i] == -1) rdfs(i, ptr), ptr++;
t.resize(ptr);
for(int i = 0; i < g.size(); i++) {
for(auto &to : g[i]) {
int x = comp[i], y = comp[to];
if(x == y) continue;
t[x].push_back(y);
}
}
}
};
検証
#define PROBLEM "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_3_C"
#include "../../template/template.cpp"
#include "../template.cpp"
#include "../strongly-connected-components.cpp"
int main() {
int V, E, Q;
scanf("%d %d", &V, &E);
UnWeightedGraph g(V), buff;
for(int i = 0; i < E; i++) {
int a, b;
scanf("%d %d", &a, &b);
g[a].emplace_back(b);
}
StronglyConnectedComponents< UnWeightedGraph > scc(g);
scc.build(buff);
scanf("%d", &Q);
while(Q--) {
int a, b;
scanf("%d %d", &a, &b);
puts(scc[a] == scc[b] ? "1" : "0");
}
}