在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量(strongly connected components)。
Tarjan算法:
假设图有n个节点,m条边。该算法可以在O(n+m)的时间复杂度中输出所有强连通分量
所用数据结构说明:
数组 dfn[]:记录每个点按照DFS被访问顺序的时间戳
数组 low[]:记录每个点所能访问到的时间戳最靠前的点的时间戳
栈 S:按顺序记录当前DFS树中的节点
算法流程:
tarjan(u){
dfn[u] = low[u] = ++index
S.push(u)
for each (u, v) in E
if (v is not visited)
tarjan(v)
low[u] = min(low[u],low[v])
else if (v in S)
low[u] = min(low[u],dfn[v])
if (dfn[u] == low[u]) {
w = S.pop()
} until (w == u) //将该点之前的所有点作为一个强连通分量出栈
}
算法原理:
1、为什么出栈的部分是强连通分量:
①设结束点为k,则对于任意非结束点i,有low[k] = dfn[k] <= low[i] < dfn[i]
②每一次出栈的节点必然是深搜树中某一棵子树的全部节点
结合以上两点,我们可以发现:这一部分的任何一个点都可以访问到结束点,结束点可以访问到任何一个点,所以任意两点间必然能够有回路,得证
对于前者,利用反证法:假设这一部分点中存在一个点无法回访到结束点,则设其能够回访到的dfn最小的点为i,则由性质①可得low[i] < dfn[i],即i可以访问到dfn更小的点,故矛盾
对于后者,由性质②结合性质①后半部分可得,结束点必为该子树的根,由DFS性质可得,其必能访问到之后的每一个点
※关于第②点,有两种考虑方法:
i)整个深搜和访问(判断low[i]与dfn[i])实际上是后序遍历,所以每一个被确定的结束点必然是一棵子树的根
ii) 反证法:如果这些点分处在多棵子树中,那么在回溯时,靠前的部分会被先从搜索树中除去(从栈中弹出)
2、为什么出栈的部分是完整的强连通分量:
假设出栈的是不完整的强连通分量,则其剩余的部分结点可能存在三种情况:
①在栈中
②尚未进栈
③之前已经出栈
对于情况②:尚未进栈意味着不存在一条由已知点通向该点的路,所以必然不可能处于该强连通分量中
对于情况①:假设此时的结束点为i,则对于栈中的任意点j,此次出栈的任意点k,有dfn[j] < dfn[i] <= low[k],即此次出栈的任意点都无法回访到尚在栈中的点,故不可能处于该强连通分量中
对于情况③:与情况①相同(此次出栈的部分等价于对之前某次出栈操作而言的“在栈中”部分)
参考链接:http://blog.youkuaiyun.com/zakheav/article/details/46424251
参考了这位老哥的证明逻辑以及对于第二个问题的证明,但是对于第一个问题,即“为什么是强连通的”,我对于他的证明存有疑问:边BA不存在于回路中为什么能够得到low[A] == dfn[A]?
A虽然不能回访到B,但可以指向他所绘图中B所在的红圈圈中的其他点,因为我们此时的条件是存在一条边不在回路中,而不是仅存在一条边不在回路中,所以B所在的红圈中可能存在点和B在不同的搜索子树上且不指向B
9273



被折叠的 条评论
为什么被折叠?



