我需要检查有向图是否强连接,换句话说,是否所有节点都可以被任何其他节点(不一定是通过直接边缘)到达。
执行此操作的一种方法是在每个节点上运行DFS和BFS,并查看所有其他节点仍可访问。
有更好的方法吗?
答案 0 :(得分:24)
考虑以下算法。
从图v
的随机顶点G
开始,然后运行DFS(G, v)
。
如果DFS(G, v)
无法覆盖图表G
中的每个其他顶点,则会有一些顶点u
,因此v
没有定向路径到u
,因此G
没有强烈关联。
如果它到达每个顶点,则会有v
到图G
中每个其他顶点的有向路径。
反转有向图G
中所有边的方向。
从DFS
开始再次运行v
。
如果DFS无法到达每个顶点,则会有一些顶点u
,这样原始图形中就没有从u
到v
的有向路径。
另一方面,如果它确实到达每个顶点,那么在原始图形中,存在从每个顶点u
到v
的有向路径。
因此,如果G“通过”两个DFS,则它是强连接的。此外,由于DFS在O(n + m)
时间运行,因此该算法在O(2(n + m)) = O(n + m)
时间内运行,因为它需要2次DFS遍历。
答案 1 :(得分:14)
Tarjan's强连接组件算法(或Gabow's变体)当然就足够了;如果只有一个强连接组件,则图形连接很强。
两者都是线性时间。
与正常深度优先搜索一样,您可以跟踪每个节点的状态:新节点,已查看但仍处于打开状态(它位于调用堆栈中),并且已查看并已完成。此外,您可以在第一次到达节点时存储深度,以及从节点可以访问的最低深度(在完成节点后就知道了这一点)。如果最低可达深度等于其自身深度,则节点是强连接组件的根。即使您从根到达节点的深度不是最小可能的深度,这也可以工作。
要检查整个图是否是单个SCC,请从任何单个节点启动dfs,当您完成时,如果最低可达深度为0,并且每个节点都被访问过,那么整个图是强烈联系。
答案 2 :(得分:2)
要检查每个节点是否都具有给定图中每个其他节点的往返路径:
Tarjan's algorithm假定每个节点的深度为d[i]
。最初,根的深度最小。然后,我们对d[i] = min(d[j])
的任何邻居j
进行后DFS更新i
。实际上,BFS也可以在此处使用归约规则d[i] = min(d[j])
。
function dfs(i)
d[i] = i
mark i as visited
for each neighbor j of i:
if j is not visited then dfs(j)
d[i] = min(d[i], d[j])
如果存在从u
到v
的转发路径,则为d[u] <= d[v]
。因此,在SCC d[v] <= d[u] <= d[v]
中,SCC中的所有节点将具有相同的深度。为了判断图是否为SCC,我们检查所有节点是否都具有相同的d[i]
。
它是Kosaraju’s algorithm的简化版本。从根开始,我们检查DFS / BFS是否可以访问每个节点。然后,反转每个边缘的方向。我们检查是否可以从同一根再次访问每个节点。参见C++ code。
答案 3 :(得分:1)
您可以计算All-Pairs Shortest Path并查看是否有无限。
答案 4 :(得分:1)
已经提到了Tarjan的算法。但我经常发现Kosaraju's Algorithm更容易理解,即使它需要两次遍历图形。 IIRC,在CLRS中也很好地解释了它。
答案 5 :(得分:1)
test-connected(G)
{
choose a vertex x
make a list L of vertices reachable from x,
and another list K of vertices to be explored.
initially, L = K = x.
while K is nonempty
find and remove some vertex y in K
for each edge (y, z)
if (z is not in L)
add z to both L and K
if L has fewer than n items
return disconnected
else return connected
}
答案 6 :(得分:0)
这样做的一种方法是为图生成Laplacian matrix,然后计算特征值,最后计算零的数量。如果只存在一个零特征值,则图形是强连接。
注意:注意为有向图创建拉普拉斯矩阵的方法略有不同。
答案 7 :(得分:0)
您可以使用Kosaraju基于DFS的简单算法来执行两次DFS遍历图:
这个想法是,如果每个节点都可以从顶点v到达,并且每个节点都可以到达v,那么图形就是强连接的。 在算法的第2步中,我们检查是否可以从v到达所有顶点。在步骤4中,我们检查所有顶点是否都可以到达v(在反向图中,如果所有顶点都可以从v到达,那么所有顶点都可以达到v原始值图)。
算法: 1)将所有顶点初始化为未访问。
2)从任意顶点开始对图进行DFS遍历v。如果DFS遍历不访问所有顶点,则返回false。
3)反转所有弧线(或找到图形的转置或反转)
4)在反转图中将所有顶点标记为未访问。
5)从相同的顶点v开始执行反向图的DFS遍历(与步骤2相同)。如果DFS遍历不访问所有顶点,则返回false。否则返回true。
时间复杂度:如果使用邻接列表表示来表示图形,则上述实现的时间复杂度与深度优先搜索相同,即O(V + E)。