求割点与桥

在学习了刘汝佳大大的蓝书后有点体会,特来小结一下.

割点:对于无向图G,如果删除某个点u后,连通分量数目增加,称u为图的割点.

桥:对于无向图G,如果删除某条边(u,v)后,连通分量数目增加,称(u,v)为图的桥.

先说说怎么求割点吧,我们可以先想怎么暴力求解:把每一个点删除一次,然后dfs看连通分量的数目的变化,不过这样复杂度O(n(n + m)),能不能优化呢?先想象一下割点是一个什么样的点:

其中A很显然是割点,D不是割点,这两个点很有特点,所以我们拿它们来分析,这个图很像一棵树,其中A是根节点,我们可以猜想一下:如果一棵树的根节点有两个或两个以上个孩子,那么根节点就是割点,这个是显然的.那么D为什么不是割点呢?C是D的祖先,F是D的儿子,儿子能连一条边到祖先,所以D就不是割点。这些分析都建立在图是一棵树的基础上,可是这根本不是树啊?我们可以考虑dfs树:

以dfs建立的一棵树(虽然并不是树)就能满足我们的要求,由此可以得到一条定理:在无向连通图G的DFS树中,非根节点u是G的割点当且仅当u存在一个子节点v,使得v及其后代都没有反向边连回u的祖先(连回u不算).

证明很简单,如果有边连回祖先,那么删除这个点后,剩下的点都能通过这条边组成一个连通分量,数目不变.

现在考虑怎么实现这个算法,设low(u)为u及其后代能连回的最早的祖先的pre值,pre值是我们认为规定的一个值,定义是dfs到节点u时,pre[u] = ++dfs_clock,  dfs_clock是一个累加器,目的是为了记录到每个节点的时间.那么u是割点当且仅当low(v) >= pre(u),v是u的子节点.这时有一个特殊情况:v的后代只能连回v自己,即low(v) > pre(u),这个时候边(u,v)和(v,u)就是桥,具体的证明可以参考上面割点的证明.

算法的具体实现:

int dfs(int u, int fa)
{
    int lowu = pre[u] = ++dfs_clock;
    int child = 0;
    for (int i = head[u]; i + 1; i = nextt[i])
    {
        int v = to[i];
        if (!pre[v])
        {
            child++;
            int lowv = dfs(v, u);
            lowu = min(lowv, lowu);
            if (lowv >= pre[u])   //记录割顶
                flag[u] = true;
            if (lowv > pre[u])   //记录桥
                flag2[u][v] = flag2[v][u] = 1;
        }
        else
            if (pre[v] < pre[u] && v != fa)   //千万不要漏掉第二个条件,这是(fa,u)的第二次访问,不是指向祖先的边!
                lowu = min(lowu, pre[v]);
    }
    if (fa < 0 && child == 1)   //特判根节点
        flag[u] = 0;return lowu;
}

初始化的时候pre全部为0,开始dfs的时候fa = -1,基本上注意点都在代码里了,至于为什么我们遇到割点不直接输出是因为一个割点可能有多个子节点满足条件,防止重复输出.

时间: 2024-10-02 07:07:25

求割点与桥的相关文章

tarjan双联通求割点和桥模板

  求割点 int n,m,stamp,low[1005],dfn[1005],iscut[1005];//iscut记录的为割点 vector<int> vec[1005]; void tarjan(int index,int fa){ int child=0; low[index]=dfn[index]=++stamp; for(int i=0;i<vec[index].size();i++) { int tmp=vec[index][i]; if(!dfn[tmp]) { chil

【转】【模板】求割点和桥

[要求]给定一个无向图,找出图中的割点个桥 [说在前面]看了这么多,想入门理解的话真心推荐“听雨草堂”这一篇,结合模板以及各数组表示的含义看,至少把我看懂了.      模板我没用她的,用的是上交红书的模板,反正都一样的东西: [几个定义] DFS搜索树:用DFS对图进行遍历时,按照遍历次序的不同,我们可以得到一棵DFS搜索树,如图(b)所示. 树边:(或称父子边),在搜索树中的实线所示,可理解为在DFS过程中访问未访问节点时所经过的边. 回边:(或称返祖边.后向边),在搜索树中的虚线所示,可理

tarjan求割点与桥——例题(9018——2100)

#include<cstdio> #include<iostream> #include<cstring> #include<vector> using namespace std; inline int read(){ int num=0,t=1;char c=getchar(); while(c>'9'||c<'0'){if(c=='-')t=-1;c=getchar();} while(c<='9'&&c>='0

图的割点、桥与双连通分支

原文地址:图的割点.桥与双连通分支 [点连通度与边连通度] 在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合.一个图的点连通度的定义为,最小割点集合中的顶点数. 类似的,如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合.一个图的边连通度的定义为,最小割边集合中的边数. [双连通图.割点与桥] 如果一个无向连通图的点连通度大于1,则称该图是点双连通的(point biconne

【求无向图的桥,有重边】ZOJ - 2588 Burning Bridges

模板题——求割点与桥 题意,要使一个无向图不连通,输出必定要删掉的边的数量及其编号.求桥的裸题,可拿来练手. 套模板的时候注意本题两节点之间可能有多条边,而模板是不判重边的,所以直接套模板的话,会将重边也当做桥输出,因此要在判断桥的时候加一个判断,即当且仅当两点之间仅有一条边,且满足dfn[cur] < low[i],(cur, i)才是桥. 另外本题节点数为105,用邻接矩阵的话会内存超限,所以我用了了一个multiset存储边及其编号. 代码如下: 1 #include<cstdio>

强连通分量、割点、桥

一.强连通分量 在有向图G中,如果任意两个不同的顶点相互可达,则该有向图为强连通的:一个有向图G的极大连通子图称为G的强连通分支:将有向图G的每一条边反向形成的图称为G的转置 Gt. 1.1 有向图的一些定理 有向无环图中唯一出度为0的点,一定可以由任何点出发到达     图中节点的数目为有限多个,而且无环,因此从任何点出发往前走,一定终止于出度为0的点,否则走N+1步(N为图中节点的数目),则必然有一个点被走了两次,形成了环,与无环矛盾! 有向无环图中所有入度不为0的点,一定可以由某个入度为0

【转载】图的割点、桥与双连通分支

[点连通度与边连通度] 在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合.一个图的点连通度的定义为,最小割点集合中的顶点数. 类似的,如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合.一个图的边连通度的定义为,最小割边集合中的边数. [双连通图.割点与桥] 如果一个无向连通图的点连通度大于1,则称该图是点双连通的(point biconnected),简称双连通或重连通.一个

【转】图的割点、桥与双连通分支

原文地址:https://www.byvoid.com/blog/biconnect 图的割点.桥与双连通分支 [点连通度与边连通度] 在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合.一个图的点连通度的定义为,最小割点集合中的顶点数. 类似的,如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合.一个图的边连通度的定义为,最小割边集合中的边数. [双连通图.割点与桥] 如果一个

割点,桥,边双连通分量,点双连通分量

(1)求割点和桥的方法是tarjan算法,刘汝佳训练指南p314. [割点]可以将两个[点双连通分量]隔开来,因为仅一个[点双连通分量]中肯定无割点,那么每两个点对都同时处于若干个简单环中才能当一个点撤掉仍然可以互通. [桥]可以将两个[边双连通分量]隔开来,因为仅仅一个[边双连通分量]中肯定无桥,那么每两个点对之间肯定有2条以上的路径可达(可以经过同1个点),当任意1条边撤掉后每两个点对仍然可达. (2)要使一个连通图变成[边双连通图],可以使用tarjian算法求出桥,每条桥隔开两个[边双连