强连通分量
连通分量要求任意两点可达,而强连通分量要求任意两点互相可达,即必须存在a->b且b->a
的路径
强连通分量问题就是求解一个图中所有的强连通分量集合。
SCC算法简介
SCC算法在《算法导论》中有介绍到,SCC算法基于dfs,通过两次dfs可以求出图中所有的连通分量,是快速的方法。
在了解SCC算法之前先介绍两个概念
两个概念
dfs结束时间
规定一种【结束时间】,表示dfs退栈时候的时间,我们可以用两个数字表示dfs进栈,退栈的时间。如下图所示,左边的数字是dfs开始时间,右边的数字是dfs结束时间。
dfs结束时间可以表示拓扑排序的序列,即结束时间大的,拓扑排序排在结束时间小的节点前面,本质上表示退栈的先后,即访问顺序
转置图
即有向图的出边改为入边
SCC算法伪代码描述
对原图dfs并且将节点按照【结束时间】从大到小排序形成序列seq[]
按照seq[]序列里面的节点顺序 对【转置图】dfs 搜到的每一个连通分支就是一个强连通分量
?当我打出❓的时候,
这也太抽象了吧,所以下面给出证明
SCC算法正确性证明
证明过程需要一些引理的帮助,下面介绍几个引理
引理1:
假设有两个强连通分量c1和c2,并且存在从c1到c2的边,那么一定不存在从c2到c1的边。
证明很简单,如果存在边从c2到c1,那么c1c2就是同一个强连通分量,而不是两个强连通分量了。
引理2:
如果c1到c2有边,那么强连通分支【c1中最晚结束节点】的结束时间,一定晚于【c2中最晚结束节点】的时间。
在正向图中,c1的结束时间一定晚于c2,那么有:
在转置图中,c2的结束时间一定晚于c1
原因也很简单,因为c1一定先于c2被访问,毕竟要到达c2必先经过c1,转置图相当于边全反过来,所以存在边从c2到c1,而由引理1,不存在边从c1到c2了,同理可得c2的结束时间晚于c1。
SCC证明
假设原图中有强连通分量c1,在转置图上按照【原图中dfs结束时间从大到小】顺序dfs,一定能够找到c1内的所有点。并且不会找到其他强连通分支内
不错找
先来证明在反向图上对c1中的点dfs,不会找到其他分支内的点,即不错找
反证法:假设原图有强连通分支c1和c2,而我们在转置图中对c1内的点dfs,能够找到c2内的点,这表明转置图中有边c1到c2,也就是说原图中有边c2到c1,那么说明c2所有点的结束时间晚于c1中的所有点,那么在转置图的dfs中,c2的点一定先于c1的点被dfs到,所有c1的点永远到不了c2的点,即不会【错找】