$\newcommand{\O}{\mathrm{O}}$ My Algorithm : kopricky アルゴリズムライブラリ

kopricky アルゴリズムライブラリ

Strongly Connected Component

コードについての説明

有向グラフの強連結成分分解を行うアルゴリズム. また強連結成分分解後の各強連結成分を頂点とする DAG を, 頂点をトポロジカル順序に番号付けした形で求める.
実装は逆辺からなるグラフを持つ必要のない Tarjan のアルゴリズムの方を用いている.

(関数)
add_edge$(u, v)$ : 有向辺$(u,v)$ を追加する
make_graph(): solve() 後に呼び出すと各強連結成分を頂点とする DAG が $graph$ に入る

時間計算量: $\O (n+m)$

コード

class SCC {
private:
    const int V;
    vector<vector<int> > G;
    vector<int> ord, low;
    stack<int> st;
    void dfs(const int u, int& tm){
        ord[u] = low[u] = tm++, st.push(u);
        for(int v : G[u]){
            if(ord[v] < 0){
                dfs(v, tm);
                low[u] = min(low[u], low[v]);
            }else if(cmp[v] < 0){
                low[u] = min(low[u], ord[v]);
            }
        }
        if(ord[u] == low[u]){
            while(true){
                const int v = st.top();
                st.pop();
                cmp[v] = cnt;
                if(v == u) break;
            }
            ++cnt;
        }
    }
public:
    vector<vector<int> > graph;
    vector<int> cmp;
    int cnt;
    SCC(const int node_size)
        : V(node_size), G(V), ord(V, -1), low(V), cmp(V, -1), cnt(0){}
    void add_edge(const int from, const int to){
        G[from].push_back(to);
    }
    int solve(){
        int tm = 0;
        for(int i = 0; i < V; ++i){
            if(ord[i] < 0) dfs(i, tm);
        }
        for(int i = 0; i < V; ++i) cmp[i] = cnt - 1 - cmp[i];
        return cnt;
    }
    void make_graph(){
        graph.resize(cnt);
        for(int i = 0; i < V; ++i){
            for(int j : G[i]){
                if(cmp[i] != cmp[j]){
                    graph[cmp[i]].push_back(cmp[j]);
                }
            }
        }
    }
};

verify 用の問題

AOJ : Strongly Connected Components 提出コード
yosupo さんの library checker : Strongly Connected Components 提出コード