无向图的连通性问题

前置知识点:图的DFS 树,DFS 序

无向图的连通分量

连通分量是指一个无向图的一个极大连通子图,连通分量中的任意两个点都存在一条路径可以直接或间接互相到达。

对于一个无向图,如何求出它的所有连通分量呢?

算法一:图上 DFS

对于一个没有访问过的点,我们从这个点开始DFS,访问所有还没有访问过的点,每访问到一个点,我们就将其标记为已访问。在某一个点 DFS 结束时,所有在这一轮访问到的点就在一 个连通分量中。显然该算法的时间复杂度为 O(n+m)O(n+m) 。

参考代码:

const int N = 1e5+5;
int n, m;
int fa[N], vis[N], root;  // fa[i]: 节点 i 所在连通分量的代表元素
int vector<int> g[N];
void dfs(int u) {
    vis[u] = 1;
    fa[u] = root;
    for(auto v : g[u]) {
        if(!vis[v])
            dfs(v);
    }
}

for(int i = 1; i <= n; i++) {
    if(!vis[i]) {
        root = i;
        dfs(i);
    }
}

算法二:并查集

通过扫描所有的边,不断合并两个连通分量,最终形成图的各个连通分量。算法时间复杂度为: O(n+mα(n))O(n+mα(n)) 。

参考代码:

const int N = 1e5+5;
int n, m;
int fa[N];
int find(int x) {
    if(fa[x] == x) return x;
    return fa[x] = find(fa[x]);
}
void  merge(int x, int y) {
    x = find(x);
    y = find(y);
    fa[x] = y;
}
int main() {
    cin >> n >> m;
    for(int i = 1; i <= n; i++) fa[i] = i;
    for(int i = 1; i <= m; i++) {
        int u, v;
        cin >> u >> v;
        merge(u, v);
    }
}

 

❓问题: 在对图进行遍历后,能否快速判断某个连通分支是一棵树?

🚩回答: 如果使用 DFS 遍历来实现,那么只要在扩展时,走到走过的节点,就说明存在“冗余的边”,不可能是树。如果使用并查集,那么在合并时如果两个节点的祖先相同,则说明存在“冗余的边”,不可能是树。

练习题

无向图的割点和桥

前置概念(定义)

点连通度 :在一个无向连通图中,如果有一个顶点集合 VV ,删除顶点集合 VV 以及与 VV 中顶点相连(至少有一端在 VV 中)的所有边后,原图不连通,就称这个点集 VV 为 割点集合 。大小为 11 的点割集又被称作 割点 。

一个图的点连通度 :最小割点集合中的顶点数。

边连通度 :在一个无向连通图中,如果有一个边集合 EE ,删除这个边集 EE 中的边以后,原图不连通,就称这个边集 EE 为 割边集合 。

一个图的边连通度 :最小割边集合中的边数。大小为 11 的边割集又被称作  。

点双连通图 :如果一个无向连通图的点连通度大于 11 ,则称该图是点双连通的(point biconnected),简称点双连通或点重连通(即删去任意一点原图仍然连通)。换句话说, 没有割点的连通图是点双连通的 。

边双连通图 :如果一个无向连通图的边连通度大于 11 ,则称该图是边双连通的(edge biconnected),简称边双连通或边重连通(即删去任意一条边原图仍然连通)。换句话说, 没有桥的连通图是边双连通的 。

割点 :一个图有割点,当且仅当这个图的点连通度为 11 时,割点集合的唯一元素被称为割点(cut point)(即删去割点原图不连通)。一个图可能有多个割点。有割点的图不一定有割边,如下图所示,结点 33 为割点,但是图中没有割边。

image-20240128171822087

割边(桥) :如果一个无向连通图的边连通度大于 11 ,则称该图是边双连通的(edge biconnected),简称双连通或重连通(即删去任意一边原图仍然连通)。一个图有桥,当且仅当这个图的边连通度为 11 时,割边集合的唯一元素被称为桥(bridge)(即删去桥原图不连通)。一个图可能有多个桥。有割边的图也不一定有割点,如下图所示。

image-20240128172231994

根据定义做两个猜想:两个割点之间的边一定是割边。割边的两个端点一定是割点。

可惜的是,这两个猜想都是错误的!反例如下图:

image-20240128172608552

上图中,结点 3,43,4 为割点,但是边 (3,4)(3,4) 不是割边。边 (7,8),(8,9)(7,8),(8,9) 为割边,但点 7,97,9 不是割点。

通俗版定义

对于一个无向图,如果把一个点删除后这个图的连通块(极大连通分量)数增加了,那么这个点就是这个图的割点(又称割顶)。

Tarjan 求无向图的割点和桥

根据著名计算机科学家 Robert Tarjan 的名字命名的 Tarjan 算法能够在线性时间内求出无向图的割点与桥,进一步可求出无向图的双连通分量。在有向图方面,Tarjan 算法能够求出有向图的强连通分量、必经点与必经边(下一节将会介绍)。Robert Tarjan 在数据结构方面也做出了很多卓有成效的工作,包括证明并查集的时间复杂度,提出斐波那契堆、Splay Tree 和 Lint-Cut Tree 等。

1. 时间戳

在图的 深度优先遍历 过程中,按照每个节点第一次被访问的时间顺序,依次给予 NN 个节点 1∼N1∼N 的整数标记,该标记就被称为“时间戳”,记为 dfn[x]dfn[x] 。

2. 搜索树

在无向连通图中任选一个节点出发进行深度优先遍历,每个点只访问一次。所有发生递归的边 (x,y)(x,y) (换言之,从 xx 到 yy 是对 yy 的第一次访问)构成一棵树,我们把它称为“无向连通图的搜索树”。当然,一般无向图(不定连通)的各个连通块的搜索树构成无向图的“搜索森林”。

下图左侧展示了一张无向连通图,绿色节点是深度优先遍历的起点,加粗的边是“发生递归”的边(假设我们在遇到多个分支时,总是优先访问最靠左的一条)。右侧展示了深度优先遍历的搜索树,并标注了节点的时间戳。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值