首页 > 其他分享 >桥与边双联通分量

桥与边双联通分量

时间:2024-08-02 09:39:40浏览次数:12  
标签:std vector 联通 bel int dfn low 分量

板子和常识

https://oi-wiki.org/graph/bcc/

板子用的是 tarjan算法2 的思想

只能跑无向图

  • 理论基础

    • SCC部分

      对于一个连通分量图,我们很容易想到,在该连通图中有且仅有一个 \(u\) 使得 $\texttt{dfn}_u=\texttt{low}_u $。该结点一定是在深度遍历的过程中,该连通分量中第一个被访问过的结点,因为它的 \(dfn\) 和 \(low\) 值最小,不会被该连通分量中的其他结点所影响。

      因此,在回溯的过程中,判定 $\texttt{dfn}_u=\texttt{low}_u $ 是否成立,如果成立,则栈中 \(u\) 及其上方的结点构成一个 SCC。

    • 桥与边双联通部分

      我们先总结出一个重要的性质,在无向图中,DFS 生成树上的边不是树边就只有非树边。

      我们联系一下求强连通分量的方法,在无向图中只要一个分量没有,那么在 DFS 生成树上,它的所有点都在同一个强连通分量中。

      反过来,在 DFS 生成树上的一个强连通分量,在原无向图中是边双连通分量。

      可以发现,求边双连通分量的过程实际上就是求强连通分量的过程

  • 板子解释

    class EdgeBC {
        const std::vector<std::vector<int>> &e;//存原来的无向图
        std::vector<int> stk; // stack
        int r = 0, cur = 0;
    
        void dfs(int x, int fa) {//dfs生成树上跑强连通分量
            dfn[x] = low[x] = cur++;
            stk[++r] = x;//把本次递归到的所有节点(也就是该联通快所有节点)压栈
    
            for (int y : e[x]) {
                if (y == fa) {//如果邻接节点 y 是当前节点的父节点,则跳过(将 fa 反转的目的是为了避免将父节点自身当作回边处理)。
                    fa = ~fa;
                    continue;
                }
              //强连通分量
                if (dfn[y] == -1) {
                    dfs(y, x);
                    low[x] = std::min(low[x], low[y]);
                } else {
                    low[x] = std::min(low[x], dfn[y]);
                }
            }
    				
            if (dfn[x] == low[x]) {//符合强连通分量条件
                int y;
                do {
                    y = stk[r--];
                    bel[y] = cntBlock;//bel[y](y结点对应的联通快编号)
                } while (y != x);
                cntBlock += 1;
            }
        }
    
    public:
        // original graph
        std::vector<int> dfn, low, bel, cutDeg;//bel[y](y结点对应的联通快编号)
        // shrinking graph
        std::vector<std::vector<int>> g;//由桥构成的无根树
        int cntBlock = 0, componentNum = 0;
    
        EdgeBC(const std::vector<std::vector<int>> &e)
            : e(e), dfn(e.size(), -1), low(e.size()), bel(e.size(), -1), cutDeg(e.size()) {
            int n = e.size();
            q.assign(n + 1, 0);
    
            for (int i = 0; i < n; i++) {
                if (dfn[i] == -1) {
                    componentNum += 1;
                    dfs(i, -1);
                }
            }
    
            g.resize(cntBlock);
            for (int x = 0; x < n; x++) {
                for (int y : e[x]) {
                    if (bel[x] == bel[y])
                        continue;
                    g[bel[x]].push_back(bel[y]);
                }
            }
        }
    };
    

怎么用

  • 求每个边双联通分量

https://www.luogu.com.cn/problem/P8436

由理论基础中:

反过来,在 DFS 生成树上的一个强连通分量,在原无向图中是边双连通分量。

显然,强连通分量就是答案

class EdgeBC {
    const std::vector<std::vector<int>> &e;
    std::vector<int> q; // stack
    int r = 0, cur = 0;

    void dfs(int x, int fa) {
        dfn[x] = low[x] = cur++;
        q[++r] = x;

        for (int y : e[x]) {
            if (y == fa) {
                fa = ~fa;
                continue;
            }
            if (dfn[y] == -1) {
                dfs(y, x);
                low[x] = std::min(low[x], low[y]);
            } else {
                low[x] = std::min(low[x], dfn[y]);
            }
        }

        if (dfn[x] == low[x]) {
            int y;
            std::vector<int> res{x};
            do {
                y = q[r--];
                bel[y] = cntBlock; 
                if (y != x) res.push_back(y);//把每个强连通分量统计进去就行
            } while (y != x);
            resEdgeBC.push_back(res);
            cntBlock += 1;
        }
    }

public:
    // original graph
    std::vector<int> dfn, low, bel, cutDeg;
    std::vector<std::vector<int>> resEdgeBC;

    // shrinking graph
    std::vector<std::vector<int>> g;//就是由割边组成的无根树
    //g.size() - 1就是割边数量
    int cntBlock = 0, componentNum = 0;

    EdgeBC(const std::vector<std::vector<int>> &e)
        : e(e), dfn(e.size(), -1), low(e.size()), bel(e.size(), -1), cutDeg(e.size()) {
        int n = e.size();
        q.assign(n + 1, 0);

        for (int i = 0; i < n; i++) {
            if (dfn[i] == -1) {
                componentNum += 1;
                dfs(i, -1);
            }
        }

        g.resize(cntBlock);
        for (int x = 0; x < n; x++) {
            for (int y : e[x]) {
                if (bel[x] == bel[y])
                    continue;
                g[bel[x]].push_back(bel[y]);
            }
        }
    }
};

void solve()
{
    int n, m; std::cin >> n >> m;
    std::vector adj(n, std::vector<int>()); for (int i = 0, u, v; i < m; i++) {std::cin >> u >> v; --u; --v; adj[u].push_back(v); adj[v].push_back(u);}
    auto res{EdgeBC(adj).resEdgeBC};
    std::cout << std::size(res) << '\n';
    for (auto& g : res) {
        std::cout << std::size(g) << ' '; for (auto& x : g) {std::cout << x + 1 << ' ';} std::cout << "\n";
    }

}

由桥的定义:

对于一个无向图,如果删掉一条边后图中的连通分量数增加了,则称这条边为桥或者割边。

那么对于一条边,如果两个顶点不属于同一个联通快,那显然就是一个桥。

对于该板子的使用,即对于 bel[x] != bel[y],\((x, y), (y, x)\) 都是桥

class EdgeBC {
    const std::vector<std::vector<int>> &e;
    std::vector<int> q; // stack
    int r = 0, cur = 0;

    void dfs(int x, int fa) {
        dfn[x] = low[x] = cur++;
        q[++r] = x;

        for (int y : e[x]) {
            if (y == fa) {
                fa = ~fa;
                continue;
            }
            if (dfn[y] == -1) {
                dfs(y, x);
                low[x] = std::min(low[x], low[y]);
            } else {
                low[x] = std::min(low[x], dfn[y]);
            }
        }

        if (dfn[x] == low[x]) {
            int y;
            do {
                y = q[r--];
                bel[y] = cntBlock; 
            } while (y != x);
            cntBlock += 1;
        }
    }

public:
    // original graph
    std::vector<int> dfn, low, bel, cutDeg;
    std::set<std::pair<int, int>> S_bridge; 

    // shrinking graph
    std::vector<std::vector<int>> g;//就是由割边组成的无根树
    //g.size() - 1就是割边数量
    int cntBlock = 0, componentNum = 0;

    EdgeBC(const std::vector<std::vector<int>> &e)
        : e(e), dfn(e.size(), -1), low(e.size()), bel(e.size(), -1), cutDeg(e.size()) {
        int n = e.size();
        q.assign(n + 1, 0);

        for (int i = 0; i < n; i++) {
            if (dfn[i] == -1) {
                componentNum += 1;
                dfs(i, -1);
            }
        }

        g.resize(cntBlock);
        for (int x = 0; x < n; x++) {
            for (int y : e[x]) {
                if (bel[x] == bel[y])
                    continue;
                g[bel[x]].push_back(bel[y]);
                S_bridge.emplace(x, y); S_bridge.emplace(y, x);//符合条件,加入集合
            }
        }
    }
};

标签:std,vector,联通,bel,int,dfn,low,分量
From: https://www.cnblogs.com/kdlyh/p/18338041

相关文章

  • 老式移动和联通标准SIM卡在2024的今天
    前言在我手里的,是一张普通联通和一张移动M-ZONE标准SIM卡桌上散落的SIM卡碎片已经说明了一切———我要把这些00后的SIM卡装入2024年的手机(图中为大卡的测试机,没那么有风险)联通输入123456,直接被锁,提示要用puk码解锁我后来再搜索puk码的时候才知道默认pin码是1234,草率了......
  • 联通国际专线产品:构建全球无缝连接新纪元
    联通国际专线产品:构建全球数据传输的坚固桥梁在全球化日益加深的今天,跨境、跨地域的数据传输已成为企业日常运营不可或缺的一部分。为了确保数据传输的安全性、高效性和稳定性,中国联通精心打造了国际以太网专线(IEPL)和国际专线(IPLC)两款国际专线产品,旨在为全球客户提供卓越的专有国......
  • 强连通分量-缩点
    初学只需要背代码就好了,而复习的时候要考虑的就多了((打牛客的时候用到,发现忘得差不多了)概念解读连通:在无向图中,从任意点A都可以到达任意点B。强连通:在有向图中,从任意点A都可以到达任意点B。弱连通:将有向图看作无向图后,从任意点A都可以到达任意点B。特殊地,单独的点......
  • 以BGP方式直连中国联通骨干网络,为客户提供全方位的互联网穿透服务
    联通IPTransit产品:以BGP直连,引领互联网穿透新纪元在数字化转型的浪潮中,互联网已成为连接世界、推动各行业创新发展的核心基础设施。面对日益增长的网络流量需求与复杂多变的网络环境,如何高效、安全地将内容推向全球用户,成为内容提供商面临的重要挑战。中国联通,作为国内领先的电......
  • DataOps 新趋势:联通数科如何利用 DolphinScheduler 实现数据一体化管理
    引言在DataOps(数据运营)的推动下,越来越多的企业开始关注数据研发和运营的一体化建设。DataOps通过自动化和流程优化,帮助企业实现数据的高效流转和管理。当前,ApacheDolphinScheduler作为一款开源的分布式调度系统,凭借其灵活的插件机制和强大的调度能力,已经成为许多企业构建数据......
  • 有向图的强连通分量
    \(\texttt{0x00}\)一些概念什么是“流图”?给定有向图\(G=\{V,E\}\),若存在\(r\inV\),满足从\(r\)出发能到达\(V\)中的所有点,则称\(G\)为一个“流图”,记为\((G,r)\),其中\(r\)称为流图的源点。在一个流图\(G=\{V,E\}\)上从\(r\)出发进行\(\operatorname{df......
  • 联通智慧商业零售解决方案,旨在为全球零售企业提供低成本、高效能的组网与通信服务
    联通智慧商业零售解决方案:驱动零售业全球布局与创新在全球化的大背景下,零售业面临着前所未有的机遇与挑战。随着消费者需求的多样化和市场环境的快速变化,零售商必须不断寻求创新,以保持竞争力。中国联通国际,凭借其全球化的资源布局与先进的网络技术,推出了一套面向零售行业的联......
  • 联通为工业及制造业提供AI与信息技术结合的一站式通信解决方案
    联通智慧智能制造解决方案:引领工业革命新篇章在第四次工业革命的浪潮中,人工智能(AI)、物联网(IoT)和大数据等前沿技术正以前所未有的速度改变着制造业的面貌。中国联通,作为国内领先的综合信息服务提供商,深刻理解这一行业变革的核心需求,精心打造了联通智慧智能制造解决方案,旨在通过AI......
  • 联通园区网联建设,打造无缝网络环境
    联通智慧仓储物流解决方案:重构物流版图的科技引擎在数字化转型的浪潮中,仓储物流行业正经历着前所未有的变革。中国联通,作为行业领军者,深谙物流仓储的内在需求与外在挑战,倾力打造了一套联通智慧仓储物流解决方案,旨在通过专业的网络服务与智能化的仓储管理,一站式解决行业痛点,为......
  • 联通智慧政府媒体解决方案
    联通智慧政府媒体解决方案:构建全球无缝沟通桥梁在全球化的今天,政府机构与媒体行业面临着前所未有的挑战与机遇。随着数字化转型的加速,对于通信质量、视频与内容传播以及信息安全的需求日益增长。中国联通,凭借其广泛的全球网络覆盖与强大的技术实力,推出了一套全新的智慧政府媒体解......