Algorithm 检查有向图是否强连通的算法
我需要检查一个有向图是否是强连通的,或者换句话说,是否所有节点都可以被任何其他节点访问(不一定通过直连边) 一种方法是在每个节点上运行DFS和BFS,并查看所有其他节点是否仍然可以访问 有更好的方法吗?强连接组件算法(或变体)当然就足够了;如果只有一个强连通分量,则该图是强连通的 两者都是线性时间 与普通的深度优先搜索一样,您可以跟踪每个节点的状态:新建、已查看但仍处于打开状态(在调用堆栈中)、已查看和已完成。此外,您还存储了第一次到达节点时的深度,以及从节点可以到达的最低深度(完成节点后您就会知道这一点)。如果最低可达深度等于节点自身的深度,则节点是强连接组件的根。即使从根节点到达节点的深度不是可能的最小值,这种方法仍然有效Algorithm 检查有向图是否强连通的算法,algorithm,directed-graph,strongly-connected-graph,Algorithm,Directed Graph,Strongly Connected Graph,我需要检查一个有向图是否是强连通的,或者换句话说,是否所有节点都可以被任何其他节点访问(不一定通过直连边) 一种方法是在每个节点上运行DFS和BFS,并查看所有其他节点是否仍然可以访问 有更好的方法吗?强连接组件算法(或变体)当然就足够了;如果只有一个强连通分量,则该图是强连通的 两者都是线性时间 与普通的深度优先搜索一样,您可以跟踪每个节点的状态:新建、已查看但仍处于打开状态(在调用堆栈中)、已查看和已完成。此外,您还存储了第一次到达节点时的深度,以及从节点可以到达的最低深度(完成节点后您就会
要仅检查整个图是否为单个SCC,请从任何单个节点启动dfs,完成后,如果最低可达深度为0,并且每个节点都已访问,然后整个图形是强连接的。您可以计算,并查看是否有无限的。一种方法是为图形生成特征值,然后计算特征值,最后计算零的数量。如果只有一个零特征值,则该图是强连通的
注:注意为有向图创建拉普拉斯矩阵的方法稍有不同。已经提到了Tarjan的算法。但我通常发现,即使它需要两次遍历图,也更容易理解。IIRC,在CLRS中也有很好的解释。考虑以下算法
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
}
G
的随机顶点v
开始,运行DFS(G,v)
- 如果
未能到达图DFS(G,v)
中的每个其他顶点,则存在一些顶点G
,这样就没有从u
到v
的定向路径,因此u
没有强连接G
- 如果它确实到达每个顶点,则有一条从
到图形v
中其他每个顶点的有向路径G
G
v
开始运行DFS
- 如果DFS无法到达每个顶点,则存在一些顶点
,因此在原始图形中没有从u
到u
的有向路径v
- 另一方面,如果它确实到达每个顶点,那么在原始图中有一条从每个顶点
到u
的有向路径v
因此,如果G“通过”两个DFS,则它是强连通的。此外,由于DFS在
O(n+m)
时间内运行,该算法在O(2(n+m))=O(n+m)
时间内运行,因为它需要两次DFS遍历。您可以使用Kosaraju基于DFS的简单算法,该算法对图形进行两次DFS遍历:
其思想是,如果每个节点都可以从顶点v到达,并且每个节点都可以到达v,那么图是强连通的。
在算法的第2步中,我们检查是否所有顶点都可以从v到达。在步骤4中,我们检查是否所有顶点都可以到达v(在反向图中,如果所有顶点都可以从v到达,则所有顶点都可以到达原始图中的v)
算法:
1) 将所有顶点初始化为未访问
2) 从任意顶点v开始对图进行DFS遍历。如果DFS遍历未访问所有顶点,则返回false
3) 反转所有圆弧(或找到图形的转置或反转)
4) 在反向图中将所有顶点标记为未访问
5) 从同一顶点v开始对反向图进行DFS遍历(与步骤2相同)。如果DFS遍历未访问所有顶点,则返回false。否则返回true
时间复杂度:上述实现的时间复杂度与深度优先搜索相同,如果图形使用邻接列表表示法表示,则深度优先搜索为O(V+E)。要检查每个节点是否与给定图形中的每个其他节点都有路径: 1.来自所有节点的DFS/BFS: 假设每个节点都有一个深度
d[i]
。最初,根的深度最小。我们对i
的任何邻居j
进行后期DFS更新d[i]=min(d[j])
。实际上,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]是可以的,但是这里肯定有更有效的方法。我相信普遍接受的名称是“有向图”,而不是“有向图”。很好!与Kosaraju查找强连接组件的算法非常相似。@Alip-两个查询:(1)我们可以使用BFS(G,v)
而不是DFS(G,v)
来查找您的算法吗?(2) 为了评估DFS是否从v到达每个顶点,我们是否可以对访问的顶点进行计数,然后比较ifc==| G.v |
?