有一种着名的算法可以找到名为Kosaraju's algorithm
的强连通组件,它使用两个DFS来解决这个问题,并在θ(|V| + |E|)
时间内运行。
首先我们在图的补充(G
R )上使用DFS来计算顶点逆向后序,然后我们在主要上应用第二个DFS图形G
通过以反向顺序取顶点来计算强连通分量。
虽然我理解算法的机制,但我并没有得到反向后序的需要。
如何帮助第二个DFS找到强连接组件?
答案 0 :(得分:2)
假设第一个DFS的结果是:
----------v1--------------v2-----------
其中“ - ”表示任何数字,强连接组件 g 中的所有顶点都出现在 v1 和 v2 之间。
按订单排序的DFS提供以下保证
总之,第一个DFS确保在第二个DFS中,先前访问过的强连接组件不能与其他未访问的强连接组件具有任何边缘点。
让我们简化图表如下:
此算法可能失败的情况可以推断为
原点图表就像g-->v
,反转图表看起来像g'<--v
。
要从v开始第二个DFS,第一个DFS生成的发布顺序必须类似于
g1, g2, g3, ..., v
但是你很容易发现从 v 开始第一个DFS也不从 g'开始都可以给你这样的帖子顺序,所以在这种情况下,它是保证是第一个DFS,第二个DFS不会从一个顶点开始,而顶点都是一个强连接组件。
类似于情况1,在情境2中,原始图表为g<--v
且反向开启为g'-->v
,保证在之前访问 v g '中的任何顶点。
答案 1 :(得分:1)
当您第一次在图表上运行DFS时,对于您访问的每个节点,您都可以从该节点获得有关可访问的所有节点的知识(您可以在首先完成DFS)。
然后,当您反转所有顶点并再次运行DFS时,对于您访问的每个节点,您都可以了解可以到达的所有节点非倒置节点图表(再次,你在第二个DFS完成后得到这个信息)。
示例:假设您的第一个DFS到达节点X.从该节点“您可以看到”您可以访问的所有邻居。 (我希望这是可以理解的)。然后,假设您的第二个DFS到达该节点X,但这次所有顶点都被反转。如果然后从您的节点X“您可以看到”任何其他节点,则意味着在反转顶点之前,可以从您现在看到的所有邻居到达节点X.通过以正确的顺序调用第二个DFS,您可以获得每个节点X在两个DFS树中可以从X到达的所有节点(因此,对于每个节点X,您获得的节点都可以从X到达并且可以到达X - 根据定义,这些是紧密连接的组件。)
答案 2 :(得分:0)
假设列表L
是节点的后DFS访问。 u->v
表示存在从u
到v
的转发路径。
如果u->v
而非v->u
,则u
必须出现在v
中L
的左处。但是,SCC中的节点,例如v
和w
可以以任意顺序出现在列表L
上。
因此,如果节点x
严格出现在列表y
上的L
之前:
x->y
和y->x
,就像v
和w
的情况一样x->y
而不是y->x
,就像u
和v
的情况一样x->y
也不是y->x
Kosaraju的算法从左向右迭代L
,并从转置图上的每个节点(边的方向相反)开始运行DFS。如果DFS可以到达某个节点并且该节点不属于任何SCC,则可以将该节点添加到当前根的SCC中。
在情况1中,我们将y
添加到x
的SCC中。在情况3中,y
和x
位于不同的SCC中。
情况2需要特别注意。在我们从y
调用DFS时,x
已经在其他SCC中,因此我们不会将x
添加到y
的SCC中。想象一下,如果在从根y
开始的DFS之前调用了从根x
开始的DFS,那么x
将被添加到y
的SCC中,这是错误的。
简而言之,第一个DFS安排了从其{strong>上的y
可以到达但不能的那些节点左。因此,第二个DFS可以避免将这样的节点y
添加到x
的SCC中。