割点,割边,强联通分量,点双联通分量,边双联通分量

联通分量u -> v, v -> u,相互可达的节点称为连通分量

求联通分量个数只需要DFS一遍即可,也可用并查集去判联通块


割点

无向图G中,删除某点u后,若联通分量数目增加,则u为此图G中的一个割点。这意味着若在连通图中删除割点,则图变得不连通。

DFS整个图,利用时间戳打下标记,可以得到定理:非根节点u是图G的割点当且仅当u存在一个子节点v,使得v及其后代都没有反向边连向u的祖先(不包括u)。DFS森林的性质对于此定理的正确性而言极其重要!若令low[u]为u及其后代所能连回的最早的祖先的dfn值(时间戳),定理又可表述为:非根节点u是图G的割点当且仅当u存在一个子节点v,使得low[v]>=dfn[u]

我的模板(特判相对比较优美)

[cpp]  view plain  copy
  1. int dfs(int u, int father)  
  2. {  
  3.    int lowu = dfn[u] = ++dfstime, lowv, child = 0;  
  4.    for (int i = 0, v; i < (int) g[u].size(); ++i)  
  5.    {  
  6.       if (!dfn[v = g[u][i]])  
  7.       {  
  8.          ++child, lowu = Min(lowu, lowv = dfs(v, u));  
  9.          if (lowv >= dfn[u]) ic[u] = 1;  
  10.       }  
  11.       else if (dfn[v] < dfn[u] && v != father)  
  12.          lowu = Min(lowu, dfn[v]);  
  13.    }  
  14.    if (father < 0 && child == 1) ic[u] = 0;  
  15.    return dfn[u] = lowu;  
  16. }  
  17.   
  18. int main()  
  19. {  
  20.    for (int u = 1; u <= n; ++u)  
  21.       if (!dfn[u]) dfs(u, -1);  
  22.    for (int i = 1; i <= n; ++i)  
  23.       if (ic[i]) ++icnum;  
  24.    printf("%d\n", icnum);//icnum为割点个数  
  25.    return 0;  
  26. }  


割边

DFS森林的基础上,若v的后代只能连回v自己,(即low[v]>dfn[u]),那么(u,v)其实就是割边,即删除此边则图G联通分量数目增加,连通图变得不连通。


强连通分量

首先明确强连通分量是有向图中才有的说法,与无向图联通分量类似,且每一个强连通分量都是原图中的极大强连通子图。如果把每个强连通分量缩成一个点,可知缩点后的新图必然是有向无环图。

一个强联通分量C在DFS森林中第一个被发现的点若为x,则C中的其他点都是x的后代!也就是每个强联通分量都是树的一棵子树。可以将问题转化为判断一个点是否为一个强联通分量中最先被发现的点。

我的模板

[cpp]  view plain  copy
  1. void dfs(int u)  
  2. {  
  3.    dfn[u] = low[u] = ++dfstime; S.push(u);  
  4.    for (int i = 0, v; i < (int) g[u].size(); ++i)  
  5.    {  
  6.       if (!dfn[v = g[u][i]]) dfs(v), low[u] = Min(low[u], low[v]);  
  7.       else if (!toscc[v]) low[u] = Min(low[u], dfn[v]);  
  8.    }  
  9.    if (low[u] == dfn[u])  
  10.       for (++scctot; ; )  
  11.       {  
  12.          int x = S.top(); S.pop();  
  13.          toscc[x] = scctot;  
  14.          if (x == u) break;  
  15.       }  
  16. }  
  17.   
  18. int main()  
  19. {  
  20.    for (int i = 1, u, v; i <= m; ++i)  
  21.       g[u = getint()].push_back(v = getint());  
  22.    for (int i = 1; i <= n; ++i)  
  23.       if (!dfn[i]) dfs(i);  
  24.    printf("%d\n", scctot);  
  25.    return 0;  
  26. }  



点双连通分量

对于一个连通图,若任意两点至少存在两条“点不重复”的路径,则此连通图是点-双连通的(一般称双连通),意味着任意的两条边都是在同一个简单环上,即内部无割顶。点-双连通的极大子图叫做双连通分量。定理:不同双联通分量最多只有一个公共点,且它一定是割顶,任意割顶都是至少两个不同双连通分量的公共点。


边双连通分量

对于一个连通图,若任意两点至少存在两条“边不重复”的路径,则此连通图是边-双连通的。意味着只需要每条边都至少在一个简单环中,即所有边都不是桥。边-双连通的极大子图叫做边-双连通分量,除了桥不属于任何边-双连通分量之外,其他每条边恰好属于一个边-双连通分量,而且把所有桥删除之后,每个联通分量对应原图中的一个边-双连通分量。


推荐GJB的几篇文章

http://www.byvoid.com/blog/scc-tarjan/  有向图强联通分量法的Tarjan算法

http://www.byvoid.com/blog/biconnect/  图的割点、桥与双联通分支


有一个很重要的概念叫做缩点

联系上文易知共有三类缩点

一。 将每个强连通分量缩成一个点

二。 将每个点双连通分量缩成一个点

三。 将每个边双连通分量缩成一个点

缩点过程其实只要把DFS求上面三种东西的过程稍作修改即可

比如求强连通分量时,我的模板每个强连通分量缩成的点即为退栈时的SCCTOT

而toscc就是由原图中点指向新图中点的映射

若需要重新建图,则for每条边看两点是否在同一强连通分量中,否则就在新图中添加一条新边


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
拓扑排序、割点割边以及连通分量是图论中的重要概念和算法。 1. 拓扑排序(Topological Sorting): 拓扑排序是对有向无环图(DAG)进行排序的一种算法。拓扑排序可以得到一个顶点的线性序列,使得对于任意一条有向边(u, v),在序列中顶点u都排在顶点v的前面。拓扑排序常用于表示任务之间的依赖关系,例如在工程项目中确定任务的执行顺序。 2. 割点割边(Cut Vertex and Cut Edge): 割点是指在无向连通图中,如果移除该顶点以及与该顶点相连的所有边,会导致图不再连通,则该顶点被称为割点割边是指在无向连通图中,如果移除该边,会导致图不再连通,则该边被称为割边割点割边的存在可以影响到图的连通性,因此在网络设计、通信等领域有着重要的应用。 3. 连通分量(Strongly Connected Component): 连通分量是指在有向图中,如果对于图中任意两个顶点u和v,存在从u到v和从v到u的路径,那么称u和v在同一个连通分量中。连通分量可以将有向图的顶点划分成若干个子集,每个子集内的顶点之间互相可达。连通分量可以用于分析网络中的关键节点,寻找网络的可靠性,以及在编译器设计中进行代码优化等领域。 这些概念和算法在图论中都有着广泛的应用,并且还有许多相关的算法和扩展。深入理解和掌握这些概念和算法,可以帮助我们更好地理解和解决各种与图相关的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值