Algorithm 检查有向图是否强连通的算法

Algorithm 检查有向图是否强连通的算法,algorithm,directed-graph,strongly-connected-graph,Algorithm,Directed Graph,Strongly Connected Graph,我需要检查一个有向图是否是强连通的,或者换句话说,是否所有节点都可以被任何其他节点访问(不一定通过直连边) 一种方法是在每个节点上运行DFS和BFS,并查看所有其他节点是否仍然可以访问 有更好的方法吗?强连接组件算法(或变体)当然就足够了;如果只有一个强连通分量,则该图是强连通的 两者都是线性时间 与普通的深度优先搜索一样,您可以跟踪每个节点的状态:新建、已查看但仍处于打开状态(在调用堆栈中)、已查看和已完成。此外,您还存储了第一次到达节点时的深度,以及从节点可以到达的最低深度(完成节点后您就会

我需要检查一个有向图是否是强连通的,或者换句话说,是否所有节点都可以被任何其他节点访问(不一定通过直连边)

一种方法是在每个节点上运行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到达每个顶点,我们是否可以对访问的顶点进行计数,然后比较if
    c==| G.v |