双连通图强连通图概念解释以及tarjan算法求解该类问题总结

本文深入探讨了无向图和有向图的连通性,包括连通图、强连通图、双连通图的概念,以及割点、桥、点双连通和边双连通的定义。文章介绍了Tarjan算法在求解无向图双连通分量(割点、桥)和有向图强连通分量中的应用,总结了常见问题的解决模板,并给出了相关编程题目的实例。
摘要由CSDN通过智能技术生成

最近看了看类的相关题,感觉简单的题过于模板,但是对于难题的转化,如果对与这方面的概念不清楚,很难写,故总结一下。
PS:博客里部分内容会和离散数学中的图论知识有联系,如果没有了解过相关知识可能比较难理解。
下文所说的割点=关节点,割边=桥=关节边。


首先声明一下,名叫Tarjan的算法有三种,分别为
(1) 有向图的强联通分量类问题
(2) 无向图的双联通分量(求割点,桥)类问题
(3) 最近公共祖先(LCA)
这里前两类问题比较相似,而第三类是解决LCA公共祖先问题的算法,这篇帖子将不会涉及。


下面我来具体解释一下各种概念

首先,先来理解一下连通图的概念
连通图,顾名思义,他所有的点应该都是连通的,这里的连通对于有向图无向图来说还是有一定区别的。

无向图

在一个无向图G中,若从顶点i到顶点j有路径相连(当然从j到i也一定有路径),则称i和j是连通的。如果图中任意两点都是连通的,那么这个无向图就是连通图,简单来说只要他的所有节点都在一起连着,没有任何一个节点与其他节点直接没有连边,那么他就是一个连通图。

有向图

如果G是有向图,那么连接i和j的路径中所有的边都必须同向。如果图中任意两点都是连通的,则称为强连通图注意:有向图需要双向都有路径,如果i可以到j而j不可以到i,那么就不是强连通图)。
强连通图,就一定还会有弱连通图,将有向图的所有的有向边替换为无向边,所得到的图称为原图的基图。如果一个有向图的基图是连通图,则有向图是弱连通图
简单理解就是,一个有向图,如果不是强连通图,把所有的边从无向看成有向,把有向图看成无向图,这时他如果变成了连通图,那么就说他是弱连通图。

上面在讲解有向图和无向图时引出了两个概念,强连通图和连通图,我先从无向图中的连通图来开始介绍

在无向图连通图的问题中,有两个概念非常重要,割点和桥,在大多数问题中都需要求这两个东西,在讲这两个东西之前,先来给大家介绍几个前置概念。

点连通度与边连通度 by kuangbin

在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合
一个图的点连通度的定义为,最小割点集合中的顶点数

类似的,如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合
一个图的边连通度的定义为,最小割边集合中的边数
简单总结:
点双连通:删掉一个点之后,图仍联通
边双连通:删掉一条边之后,图仍联通

双连通

定义:在无向连通图中,如果删除该图的任何一个结点或边都不能改变该图的连通性,则该图为双连通的无向图。,和点连通度与边连通度来结合这来说,就是点连通度或边连通度大于1的图。
ps:这部分概念理解知道就好,对于做题来说帮助不是很大。

双连通图割点与桥 by kuangbin

如果一个无向连通图的点连通度大于 1,则称该图是点双连通的 (point biconnected),简称双连通或重连通。一个图有割点,当且仅当这个图的点连通度为 1,则割点集合的唯一元素
被称为割点 (cut point),又叫关节点 (articulation point)。

这里割点的概念就出来了,大概意思就是,如果连通图里有一个点,把这个点和他所连接的边删掉,那么他就不连通了,那么这个点就叫做割点,下图标红的点就是割点

在这里插入图片描述(图源自网络,侵删)

理解了割点,那么理解割边也就很容易了

如果一个无向连通图边连通度大于 1,则称该图是边双连通的 (edge biconnected),简称
连通或重连通
一个图有桥,当且仅当这个图的边连通度为 1,则割边集合的唯一元素被称为 (bridge),又叫关节边 (articulation edge)。
下图标红的边就是割边
在这里插入图片描述图源自网络,侵删)

可以看出,点双连通与边双连通都可以简称为双连通,它们之间是有着某种联系的,下文中提到的双连通,均既可指点双连通,又可指边双连通。
PS:而如果有桥,这个图必有割点,如果有割点,不一定会有桥,这个很好证明,看看图就知道了。

总结:若一个无向图中的去掉任意一个节点(一条边)都不会改变此图的连通性,即不存在割点(桥),则称作点(边)双连通图。

相信看过上面如此详细的概念,大家对割点和割边已经有了深刻的认识了,那么这里就给大家求割点和割边的两道入门题,学习如何用求tarjan算法求割点割边,可以在啊哈算法中看相应章节,个人感觉是市面上能找到资料里写的最好的了。
luogu P3388 【模板】割点(割顶)

#include<cstdio> 
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
vector<int> g[20010];
int dfn[20010],low[20010],iscut[20010],son[20010];
int deep,root,n,m,ans;
int tarjan(int u,int fa)
{
   
    int child=0,lowu;
    lowu=dfn[u]=++deep;
    int sz=g[u].size();
    for(int i=0;i<sz;i++)
    {
   
        int v=g[u][i];
        if(!dfn[v])
        {
   
            child++;
            int lowv=tarjan(v,u);
            lowu=min(lowu,lowv);
            if(lowv>dfn[u])
            {
   
                iscut[u]=1;
            }
        }
        else
        {
   
            if(v!=fa&&dfn[v]<dfn[u])
            {
   
                lowu=min(lowu,dfn[v]);
            }
        } 
    }
    if(fa<0&&child==1)
    {
   
        iscut[u]=false;
    }
    low[u]=lowu;
    return lowu;
} 

int main(){
   
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
   
        int from,to;
        scanf("%d%d",&from,&to);
        g[from].push_back(to);
        g[to].push_back(from);
    }
    for(int i=1;i<=n;i++){
   
        if(!dfn[i]){
   
            root=i;
            tarjan(i,-1);
        }
    }
    for(int i=1;i<=n;i++){
   
        if(iscut[i]){
   
            ans++;
        }
    }
    printf("%d\n",ans);
    for(int i=1;i<=n;i++){
   
        if(iscut[i]){
   
            printf("%d ",i);
        }
    }
}

luogu P1656 炸铁路(割边)

#include<cstdio> 
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

vector<pair<int,int>>bridge;
vector<int> g[10010];
int dfn[10010],low[10010];
int deep,root,n,m,ans;
bool cmp(pair<int,int> a,pair<int,int> b){
   
    if(a.first == b.first)
        return a.second < b.second;
    else
        return a.first < b.first;
}
  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Randy__Lambert

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值