ホームに戻る
強連結成分分解

//有向グラフにて強連結成分分解は閉路の検出を行います。
//無向グラフではすべてが連結成分になってしまうので不可。
//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;
}

inserted by FC2 system