ホームに戻る
強連結成分分解
//有向グラフにて強連結成分分解は閉路の検出を行います。
//無向グラフではすべてが連結成分になってしまうので不可。
//O(|E|+|V|) です。
//ae(from,to) で枝を登録します。
//scc() で強連結成分分解を実行。
//cmp[i] を調べるとノードがどの閉路の構成成分かわかります。
#define MAX_V 50
vector<int> graph[MAX_V];
vector<int> rev_graph[MAX_V];
bool visited[MAX_V];
int cmp[MAX_V];
vector<int> st;
void ae(int from, int to){
graph[from].pb(to);
rev_graph[to].pb(from);
}
void dfs(int v){
visited[v] = true;
for(int i=0; i<(int)graph[v].size(); i++){
int u = graph[v][i];
if(!visited[u]){
dfs(u);
}
}
st.push_back(v);
}
void rev_dfs(int v, int cnt){
visited[v] = true;
for(int i=0; i<(int)rev_graph[v].size(); i++){
int u = rev_graph[v][i];
if(!visited[u]){
rev_dfs(u, cnt);
}
}
cmp[v] = cnt;
}
void scc(){
memset(visited, 0, sizeof(visited));
memset(cmp, 0, sizeof(cmp));
st.clear();
for(int i=0; i<MAX_V; i++){
if(!visited[i]){
dfs(i);
}
}
memset(visited, 0, sizeof(visited));
int cnt = 0;
while(!st.empty()){
int v = st.back();
st.pop_back();
if(!visited[v]){
rev_dfs(v, cnt++);
}
}
}
int from[5] = {0,1,2,3,3};
int to[5] = {1,2,3,1,4};
// 以下のグラフでは 1,2,3 が閉路
//
// 0→1→2
// ↑ ↓
// --3→4
//
// 結局 0→(123)→4 のグラフとみなす。
int main(){
rep(i,0,5){
ae(from[i],to[i]);
}
scc();
rep(i,0,5){
cout << cmp[i] << endl;
}
return 0;
}