zoukankan      html  css  js  c++  java
  • 【图论】边双连通分量

    不存在桥的图,称为边双连通图。原图可以经过tarjan算法求出桥,桥就连接了两个边双连通分量,假如把桥的都堵住(注意是只能把桥堵住,不能堵住点),然后每一块找一次连通块,就可以找到每个点所属的双连通分量,然后可以缩点成一棵树。

    struct EBCC {
    
        static const int MAXN = 2e5 + 10;
        static const int MAXM = 2e6 + 10;
    
        int n, m, t;
    
        struct Edge {
            int v, nxt;
        } e[MAXM << 1];
        int h[MAXN];
    
        int dfn[MAXN], low[MAXN];
        bool brg[MAXM];
    
        int col[MAXN];
        vector<int> ebcc[MAXN];
    
        void Init(int n) {
            this->n = n, m = 1;
            for(int i = 1; i <= n; ++i)
                h[i] = 0;
        }
    
        void AddEdge(int u, int v) {
            if(u == v) {
                m += 2;
                return;
            }
            e[++m] = {v, h[u]}, h[u] = m;
            e[++m] = {u, h[v]}, h[v] = m;
        }
    
        void dfs(int u, int from) {
            dfn[u] = low[u] = ++t;
            for(int i = h[u]; i; i = e[i].nxt) {
                int v = e[i].v;
                if(!dfn[v]) {
                    dfs(v, i ^ 1);
                    low[u] = min(low[u], low[v]);
                    if(low[v] > dfn[u])
                        brg[i / 2] = 1;
                } else if(i != from)
                    low[u] = min(low[u], dfn[v]);
            }
        }
    
        void GetBridges() {
            t = 0;
            for(int i = 1; i <= n; ++i)
                dfn[i] = low[i] = 0;
            for(int i = 2; i <= m; i += 2)
                brg[i / 2] = 0;
            for(int i = 1; i <= n; ++i) {
                if(!dfn[i])
                    dfs(i, 0);
            }
        }
    
        void dfs2(int u, int color) {
            col[u] = color, ebcc[color].eb(u);
            for(int i = h[u]; i; i = e[i].nxt) {
                if(brg[i / 2])
                    continue;
                int v = e[i].v;
                if(!col[v])
                    dfs(v, color);
            }
        }
    
        void GetEBCC() {
            GetBridges();
            for(int i = 1; i <= n; ++i)
                col[i] = 0, ebcc[i].clear();
            int n2 = 0;
            for(int i = 1; i <= n; ++i) {
                if(!col[i]) {
                    ++n2;
                    dfs2(i, n2);
                }
            }
            for(int i = 2; i <= m; i += 2) {
                if(brg[i / 2]) {
                    int u = e[i].v, v = e[i + 1].v;
                    // AddBridge(u,v)
                }
            }
        }
    
    } ebcc;
    

    问题:加最少的边,使得无向图变成边双连通图。

    首先,缩点。然后特判剩下的树是否只有1个点,是就返回。

    否则,从根开始dfs给叶子们编号。假如树有cnt个叶子,若cnt为偶数,那么第i个叶子和第i+cnt/2个叶子连边(保证至少有一对点的LCA跨越根,并且根的每条出边都被跨越)。 但是为什么呢。dfs序中,一个子树是dfs区间是连续的。

    有的算法是说找每次LCA最高的两个叶子连接(例如Claris的),但是这个是错的,例如一个“天”字形的图。

  • 相关阅读:
    HTML元素解释
    Java命名规范
    HDU 1058 Humble Numbers(DP,数)
    HDU 2845 Beans(DP,最大不连续和)
    HDU 2830 Matrix Swapping II (DP,最大全1矩阵)
    HDU 2870 Largest Submatrix(DP)
    HDU 1421 搬寝室(DP)
    HDU 2844 Coins (组合背包)
    HDU 2577 How to Type(模拟)
    HDU 2159 FATE(二维完全背包)
  • 原文地址:https://www.cnblogs.com/purinliang/p/14410418.html
Copyright © 2011-2022 走看看