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

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

Functional Graph

コードについての説明

Functional Graph とは各頂点の出次数がちょうど $1$ の単純な有向グラフのことである. グラフが $\{ 1, \ldots ,n \} \rightarrow \{ 1, \ldots ,n \}$ の関数として表現できることがその名の由来であると思われる.
定義よりグラフはループと(無向グラフと見たとき)ループ上の頂点を根とする木からなるグラフになる.

(関数)
solve(): ループ上の頂点を $loop$ の配列に入れる.
make_graph(): (無向グラフと見たとき)ループ上の頂点を根とする木たちをループ側から端に向かう方向(元とは逆の方向)の有向森とみたグラフを構築する.

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

コード

// すべての頂点の出次数が 1 のグラフ
// loop に辺に沿ったループ上の頂点が入る
// visit[v] は頂点 v が i(0_indexed) 番目のループ上の頂点なら i+1 (≧ 1),
// v がループ上になく, i 番目のループにたどり着く場合 -(i+1) (≦ -1) が格納される.
// make_graph() でループから葉へ向かう方向の森を構築

class FunctionalGraph {
private:
    const int V;
    int loop_id;
    vector<int> nx;
    void make_loop(const int st, int nw, vector<int>& vec){
        while(nx[nw] != st){
            vec.push_back(nx[nw]);
            visit[nx[nw]] = loop_id;
            nw = nx[nw];
        }
    }
    int dfs(int u, vector<int>& vec){
        visit[u] = -loop_id;
        int v = nx[u];
        if(visit[v] == -loop_id){
            vec.push_back(u), vec.push_back(v);
            visit[u] = visit[v] = loop_id;
            make_loop(u, v, vec);
            loop_id++;
            return 0;
        }else if(visit[v] == 0){
            const int res = dfs(v, vec);
            if(res == 0) return 0;
            else return visit[u] = res;
        }
        return visit[u] = (visit[v] > 0 ? -visit[v] : visit[v]);
    }
    void make_graph(){
        graph.resize(V);
        for(int i = 0; i < V; i++){
            if(visit[i] < 0) graph[nx[i]].push_back(i);
        }
    }

public:
    vector<int> visit;
    vector<vector<int> > loop, graph;
    FunctionalGraph(const int node_size)
        : V(node_size), loop_id(1), nx(V, 0), visit(V, 0){}
    void add_edge(int u, int v){
        nx[u] = v;
        if(u == nx[u]) visit[u] = loop_id++, loop.push_back({u});
    }
    void solve(){
        for(int i = 0; i < V; i++){
            if(visit[i] == 0){
                vector<int> vec;
                dfs(i, vec);
                if(!vec.empty()) loop.push_back(move(vec));
            }
        }
        // make_graph();
    }
};

verify 用の問題

JOI : 報告(report) 提出コード