zoukankan      html  css  js  c++  java
  • 模板

    这个算法是自己实现的Kosaraju算法,附带一个缩点,其实缩点这个跟Kosaraju算法没有什么关系,应该其他的强连通分量算法计算出每个点所属的强连通分量之后也可以这样缩点。

    算法复杂度:
    Kosaraju算法:初始化,加边,两次dfs,复杂度O(n+m)
    强连通分量缩点算法:遍历每个点每条边,复杂度O(n+m)
    对边排序去重:复杂度O(n+mlogm)

    注意:
    1、最好先 Init() ,然后再 AddEdge()
    2、维护缩点时点的性质对新点的影响在 dfs2() 中进行
    3、维护缩点时边的性质对新点的影响在 Build() 中进行,特别注意缩点之后的自环
    4、并不是每道题都需要原图反图,也并不是都需要对边进行去重

    Kosaraju算法缩点的结果本身就是按拓扑序排列的。

    namespace SCC {
        int n;
        vector<int> G[MAXN + 5], BG[MAXN + 5];
    
        int c1[MAXN + 5], cntc1;
        int c2[MAXN + 5], cntc2;
        int s[MAXN + 5], cnts;
    
        int n2;
        vector<int> V2[MAXN + 5];
        vector<int> G2[MAXN + 5], BG2[MAXN + 5];
    
        void Init(int _n) {
            n = _n;
            cntc1 = 0, cntc2 = 0, cnts = 0;
            for(int i = 1; i <= n; ++i) {
                G[i].clear();
                BG[i].clear();
                c1[i] = 0;
                c2[i] = 0;
                s[i] = 0;
                V2[i].clear();
                G2[i].clear();
                BG2[i].clear();
            }
            return;
        }
    
        void AddEdge(int u, int v) {
            G[u].push_back(v);
            BG[v].push_back(u);
            return;
        }
    
        void dfs1(int u) {
            c1[u] = cntc1;
            for(auto &v : G[u]) {
                if(!c1[v])
                    dfs1(v);
            }
            s[++cnts] = u;
        }
    
        void dfs2(int u) {
            V2[cntc2].push_back(u);
            c2[u] = cntc2;
            for(auto &v : BG[u]) {
                if(!c2[v])
                    dfs2(v);
            }
            return;
        }
    
        void Kosaraju() {
            for(int i = 1; i <= n; ++i) {
                if(!c1[i]) {
                    ++cntc1;
                    dfs1(i);
                }
            }
            for(int i = n; i >= 1; --i) {
                if(!c2[s[i]]) {
                    ++cntc2;
                    dfs2(s[i]);
                }
            }
            return;
        }
    
        void Build() {
            n2 = cntc2;
            for(int i = 1; i <= n2; ++i) {
                for(auto &u : V2[i]) {
                    for(auto &v : G[u]) {
                        if(c2[v] != i) {
                            G2[i].push_back(c2[v]);
                            BG2[c2[v]].push_back(i);
                        }
                    }
                }
            }
            for(int i = 1; i <= n2; ++i) {
                sort(G2[i].begin(), G2[i].end());
                G2[i].erase(unique(G2[i].begin(), G2[i].end()), G2[i].end());
                sort(BG2[i].begin(), BG2[i].end());
                BG2[i].erase(unique(BG2[i].begin(), BG2[i].end()), BG2[i].end());
            }
            return;
        }
    
        void Solve() {
            for(int i = 1; i <= n2; ++i) {
                for(auto &u : V2[i]) {
                    //把原图的信息传递给新图;
                }
            }
            //在新图上Solve;
            return;
        }
    }
    

    好像在不开O2的情况下这个vector版的比链式前向星版的费多了很多时间。

    使用方法:

    1. Init,传入原图的点数。
    2. 使用AddEdge逐个加入有向边
    3. 调用Kosaraju划分强连通分量(V2存储强连通缩点后的新点包含原图的哪些点,c2存储原图的点对应强连通缩点后的哪个新点)。
    4. 调用Build在强连通缩点之后的新点之间建立新边到G2,并排序去重。
    5. 在Solve中书写在DAG中求解的代码,例如先把原图的点的信息传递给强连通缩点后的新点,然后在DAG上dp(注意是使用G2)。
  • 相关阅读:
    JAVA多态
    JAVA中的继承
    Nginx配置中root和alisa指定文件路径的区别
    NGINX配置详解
    Jenkins填坑之邮件模板分享
    jenkins填坑之HTML报告样式问题
    Jenkins填坑之仅获取本次构建的HTML报告作为附件发送邮件
    Jenkins填坑之发送邮件无法获取HTML报告作为附件
    jenkins填坑之邮件模板中的变量无法正常获取值
    Jenkins填坑之构建ant项目时,执行结果提示input file xxx.jtl does not exist
  • 原文地址:https://www.cnblogs.com/KisekiPurin2019/p/11854474.html
Copyright © 2011-2022 走看看