连通图学习笔记

本文介绍了连通图的概念,包括无向图和有向图,强调了双连通图的特性。无向图中割点和割边的讨论,以及有向图中的强连通图和弱连通图。点双连通和边双连通分量的定义和性质被详细阐述,并探讨了它们在图论问题中的应用。文章总结了双连通分量的常见模型和问法,以及强连通分量的问题求解策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

连通图

无向图有向图的区别

无向图

任意两点都相互能到达
无向图割点

bool ge[maxn];
int dfn[maxn],low[maxn],dfscnt;
void tarjan(int x,int rt){
	dfn[x]=low[x]=++dfscnt;
	int child=0;
	for(int i=head[x];i;i=nex[i]){
		int y=to[i];
		if(!dfn[y]){
			tarjan(y,rt);
			low[x]=min(low[x],low[y]);
			if(x==rt)child++;
			else if(low[y]>=dfn[x])ge[x]=1;
		}
		else low[x]=min(low[x],dfn[y]);
	}
	if(x==rt&&child>=2)ge[x]=1;
}

无向图割边

void tarjan(int u, int fa) {
    dfn[u] = low[u] = ++idx;
    for (int i = h[u]; ~i; i = e[i].next) {
        int v = e[i].to;
        if(v == fa) continue;
        if (!dfn[v]) {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            if (low[v] > dfn[u]) flag[i]=flag[i^1]=1;, brg_num++;
        }
        else
            low[u] = min(low[u], dfn[v]);
    }
}

有向图

强连通图: 任意两点都能相互到达
弱连通图: 基图是连通图

点双连通: 删掉一个点之后,图仍联通
边双连通: 删掉一条边之后,图仍联通

有向图强连通分量

void Tarjan(LL u){
    dfn[u]=low[u]=++tim; sta[++top]=u; visit[u]=true;
    for(LL i=head[u];i;i=dis[i].nxt){
        LL v=dis[i].to;
        if(!dfn[v]){
            Tarjan(v); low[u]=std::min(low[u],low[v]);
        }else if(visit[v]) low[u]=std::min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        LL now; ++nod;
        do{
            now=sta[top--]; col[now]=nod; visit[now]=false;}while(now!=u);
    }
}

性质:

  1. 如果有桥,这个图必有割点,如果有割点,不一定会有桥
  2. Tarjan算法只适用于求有向图的割点,直接套Tarjan模板用来求无向图割点会出错的

总结:

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


双连通分量

双连通分量分为边双连通分量和点双连通分量两种

边双连通分量

概念: 在分量内的任意两个点总可以找到两条边不相同的路径互相到达。总而言之就是一个圈,正着走反着走都可以相互到达,至少只有一个点。也就是同一边双内,点与点的边集中无桥,注意割边不属于任何一个边双联通分量

性质:
1.遇到一个桥的时候就说明有两个边双联通分量

void Tarjan(LL u,LL fa){
    dfn[u]=low[u]=++tim; sta[++top]=u;
    for(LL i=head[u];i;i=dis[i].nxt){
        LL v(dis[i].to);
        if(v==fa) continue;
        if(!dfn[v]){
            Tarjan(v,u); low[u]=std::min(low[u],low[v]);
        }else low[u]=std::min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        LL now; ++nod;
        do{
            now=sta[top--]; col[now]=nod;
        }while(now!=u);
    }
}

点双连通分量

概念
删掉一个点之后,图仍联通

性质:
1.割点会同时出现在多个点双联通分量中
2.非割点只会出现在一个点连通分量中
3.每遍历一个儿子就计算是否有点连通分量;
4.割顶可以属于多个连通分量,请注意与割边区分;
5.当i为根节点时,至少要有两个儿子才能是割点;

void Tarjan(LL u){
    dfn[u]=low[u]=++tim; sta[++sta[0]]=u;
    for(LL i=G1.head[u];i;i=G1.dis[i].next){
        LL v(G1.dis[i].to);
        if(!dfn[v]){
            Tarjan(v);
            low[u]=min(low[u],low[v]);
            if(low[v]>=dfn[u]){
                G2.Add(++tot,u); LL now(0);
                do{
                    now=sta[sta[0]--];
                    G2.Add(tot,now);
                }while(now!=v);
            }
        }else low[u]=min(low[u],dfn[v]);
    }
}

【双连通分量常见的模型和问法】

1.给出的图是非连通图,如:
A.有一些点,一些边,加最少的边,要使得整个图变成双联通图。
大致方法: 求出所有分量,把每个分量看成一个点,统计每个点的度,有一个度为一则cnt加1,答案为(cnt+1)/2;

2.给出的图是连通图,如:
A.给定一个起点一个终点,求各种问题是否能实现。
大致方法: 求出所有分量,并把每个分量当成点,于是问题得到化简;

【强连通分量常见的模型和问法】

1.给出的是非连通图,如:
A.有一些点,一些有向边,求至少加多少边使任意两个点可相互到达
大致方法: 求出所有的分量,缩点,分别求出出度入度为0的点的数量,取多的为答案;
B.有一些点,一些有向边,求在这个图上走一条路最多可以经过多少个点
大致方法: 求出所有的分量,缩点,形成一个或多个DAG图,然后做DAG上的dp
C.有一些点,一些有向边,给出一些特殊点,求终点是特殊点的最长的一条路
大致方法: 求出所有分量,并标记哪些分量有特殊点,然后也是DAG的dp

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值