算法复习——图算法篇之强连通分量

算法复习——图算法篇之强连通分量

以下内容主要参考中国大学MOOC《算法设计与分析》,墙裂推荐希望入门算法的童鞋学习!

1. 问题背景

  • 社交圈划分

    • 如何把人群按通话记录划分成不同的社交圈?
    • 如果闭环通话,说明关系相对密切;如果单向通话,说明关系相对疏远。

在这里插入图片描述

  • 强连通分量(有向图

    • 一个强连通分量是顶点的子集
    • 强连通分量中任意两点相互可达
    • 满足最大型加入新顶点,不保证相互可达
    • 特性:任意两强连通分量不相交
      • 反证易得,若相交,破坏了最大性

在这里插入图片描述

2. 问题定义

强连通分量(Strongly Connected Components)

输入:

  • 有向图 G = < V , E > G=<V, E> G=<V,E>

输出:

  • 图的所有强连通分量 C 1 , C 2 , … , C n C_1, C_2, \dots, C_n C1,C2,,Cn

在这里插入图片描述

3. 算法框架

在这里插入图片描述

步骤1:把边反向,得到反向图 G R G^R GR

在这里插入图片描述

步骤2:在 G R G^R GR上执行DFS,得到顶点完成时刻顺序 L L L

​ 例如,得到的 L L L如下所示:

在这里插入图片描述

步骤3:在 G G G上按 L L L逆序执行DFS,得到强连通分量

4. 伪代码

Strongly-Connected-Component(G)

输入:图G

输出:强连通分量

R ← {}
G_R ← G.reverse()
L ← DFS(G_R)
color[1..V] ← WHITE
for i ← L.length() downto 1 do
	u ← L[i]
	if color[u] = WHITE then
		L_scc ← DFS-Visit(G, u)
		R ← R ∪ set(L_scc)
	end
end
return R

DFS(G)

输入:图G

现金数组color[1..V],L[1..V]
for v ∈ V do
	color[v] ← WHITE
end
for v ∈ V do
	if color[v] = WHITE then
		L' ← DFS-Visit(G, v)
		向L结尾追加L'
	end
end

DFS-Visit(G, v)

输入:图G,顶点v

输出:按完成时刻从早到晚排列的顶点L

color[v] ← GRAY
for w ∈ G.Adj[v] do
	if color[w] = WHITE then
		L ← DFS-Visit(G, w)
	end
end
color[v] ← BLACK
向L结尾追加结点v
return L

​ 该算法的时间复杂度是 O ( ∣ V ∣ + ∣ E ∣ ) O(|V|+|E|) O(V+E)

5. 算法正确性证明

在这里插入图片描述

  • 强连通分量图 G S C C G^{SCC} GSCC把强连通分量看作一个点,得到有向图

在这里插入图片描述

  • 性质: G S C C G^{SCC} GSCC一定是有向无环图

  • 反证:若存在环,两强连通分量中顶点相互可达,与最大性矛盾

  • S C C S i n k SCC_{Sink} SCCSink G S C C G^{SCC} GSCC中出度为0的点

    在这里插入图片描述

    • 性质1: G S C C G^{SCC} GSCC中至少存在一个 S C C S i n k SCC_{Sink} SCCSink
    • 性质2:删除 S C C S i n k SCC_{Sink} SCCSink,会产生新的 S C C S i n k SCC_{Sink} SCCSink
    • 反证:若不存在,所有点均有出度,必存在环;而无环图子图必无环,矛盾

​ 结合性质观察算法第2次DFS,第2次DFS恰恰是按照 S C C S i n k SCC_{Sink} SCCSink的顺序搜索,每次搜索恰好访问该SCC的所有点。

​ 那么问题就是为什么通过按 L L L逆序执行DFS实现,就可以保证第2次DFS按照 S C C S i n k SCC_{Sink} SCCSink的顺序搜索且每次搜索恰好访问该SCC的所有点?

在这里插入图片描述

  • 给定反向图 G R G^R GR,存在边 ( u , v ) (u, v) (u,v) u ∈ S C C 1 u \in SCC_1 uSCC1 v ∈ S C C 2 v \in SCC_2 vSCC2(在原始图 G G G中, S C C 1 SCC_1 SCC1 S C C s i n k SCC_{sink} SCCsink

在这里插入图片描述

  • 若先搜索 u u u,会从 u u u搜索 v v v,则 f ( v ) < f ( u ) f(v)<f(u) f(v)<f(u)

  • 若先搜索 v v v v v v搜索完成才开始搜索 u u u,则 f ( v ) < f ( u ) f(v)<f(u) f(v)<f(u)

  • 可知在 L L L G R G^R GR上DFS完成时刻顺序)中 v v v一定在 u u u前面

在这里插入图片描述

  • 所以按 L L L的逆序,总是先搜索 u u u,符合 S C C s i n k SCC_{sink} SCCsink的顺序

  • 因此我们就证明了按 L L L逆序执行DFS实现确实可以保证第2次DFS按照 S C C s i n k SCC_{sink} SCCsink的顺序搜索。

在这里插入图片描述

  • 在强连通分量内,顶点相互可达 → DFS可以访问到该 S C C SCC SCC所有点
  • S C C s i n k SCC_{sink} SCCsink出度为0 → DFS不会访问该 S C C SCC SCC以外的点

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值