Algorithm 为什么我们需要在Kosaraju';s算法?

Algorithm 为什么我们需要在Kosaraju';s算法?,algorithm,depth-first-search,kosaraju-algorithm,Algorithm,Depth First Search,Kosaraju Algorithm,有一个著名的算法可以找到强连接的组件,称为Kosaraju算法,它使用两个DFS来解决这个问题,并在θ(|V |+| E |)时间内运行 首先,我们使用图的补码(GR)上的DFS来计算顶点的反向后序,然后,我们在主图G上应用第二个DFS,以反向后序取顶点来计算强连通分量 虽然我理解算法的机制,但我并没有得到反向后序需求背后的直觉 如何帮助第二个DFS找到强连接的组件?假设第一个DFS的结果是: ------------v1-------v2------- 其中“-”表示任意数字,强连接组件g中的

有一个著名的算法可以找到强连接的组件,称为
Kosaraju算法
,它使用两个DFS来解决这个问题,并在
θ(|V |+| E |)时间内运行

首先,我们使用图的补码(
G
R)上的DFS来计算顶点的反向后序,然后,我们在主图
G
上应用第二个DFS,以反向后序取顶点来计算强连通分量

虽然我理解算法的机制,但我并没有得到反向后序需求背后的直觉


如何帮助第二个DFS找到强连接的组件?

假设第一个DFS的结果是:

------------v1-------v2-------

其中“-”表示任意数字,强连接组件g中的所有顶点都出现在v1和v2之间

邮购DFS提供以下保证:

  • v2之后的所有顶点不会指向反向图中的g(也就是说,无法从原点图中的g到达这些顶点)
  • v1之前的所有顶点不能从反向图中的g指向(也就是说,不能从原点图中的这些顶点指向g)
一句话,第一个DFS确保在第二个DFS中,先前访问的强连接组件不能有任何到其他未访问的强连接组件的边缘点

一些详细的解释 让我们将图表简化如下:

  • 整个图是G
  • G包含两个强连通分量,一个是G,另一个是单顶点v
  • 在v和g之间只有一条边,从v到g或从g到v,这条边的名称是e
  • g',e'代表g,e的反面
该算法可能失败的情况可归纳为

  • 从v开始DFS,e'点从v到g'
  • 从g'内的顶点开始DFS,e'点从g'到v
  • 对于情景1 原点图类似于
    g-->v
    ,反向图类似于
    g'v
    ,可以保证v在g'中的任何顶点之前被访问

  • 当您第一次在图形上运行DFS时,对于您访问的每个节点,您都会获得有关可从该节点访问的所有节点的信息(在第一次DFS完成后,您会获得此信息)

  • 然后,当您反转所有顶点并再次运行DFS时,对于您访问的每个节点,您都可以在非反转图中获得有关可以到达该节点的所有节点的知识(同样,在第二次DFS完成后,您可以获得此信息)


  • 示例:假设您的第一个DFS到达节点X。从该节点“您可以看到”您可以访问的所有邻居。(我希望这是可以理解的)。然后,假设第二个DFS到达该节点X,但这次所有顶点都反转。如果然后从节点X“您可以看到”任何其他节点,这意味着在反转顶点之前,可以从您现在看到的所有邻居访问节点X。通过以正确的顺序调用第二个DFS,您可以为每个节点X获得两个DFS树中从X可以到达的所有节点(因此,对于每个节点X,您可以获得从X可以到达并且可以到达X的节点-根据定义,这些是强连接的组件).

    假设列表
    L
    是节点的后订单DFS访问
    u->v
    表示存在从
    u
    v
    的转发路径

    如果
    u->v
    而不是
    v->u
    ,则
    u
    必须出现在
    L
    v
    左侧。然而,SCC中的节点,例如
    v
    w
    ,可以在列表
    L
    上以任意顺序出现

    因此,如果一个节点
    x
    严格地出现在列表
    L
    上的
    y
    之前:

    • 案例1:
      x->y
      y->x
      ,与
      v
      w
    • 案例二:
      x->y
      而不是
      y->x
      ,就像
      u
      v
    • 案例3:非
      x->y
      和非
      y->x
    Kosaraju的算法从左到右迭代
    L
    ,并从转置图上的每个节点开始运行DFS(其中边的方向是反向的)。如果DFS可以访问某个节点,并且该节点不属于任何SCC,则我们将该节点添加到当前根的SCC中

    在案例1中,我们将在
    x
    的SCC中添加
    y
    。在情况3中,
    y
    x
    位于不同的SCC中

    案例2需要特别注意。当我们从
    y
    调用DFS时,
    x
    已经在一些其他SCC中,因此我们不会将
    x
    添加到
    y
    的SCC中。想象一下,如果在从根开始的DFS
    x
    之前调用从根开始的DFS
    y
    ,则
    x
    将添加到
    y
    的SCC中,这是错误的

    简言之,第一个DFS排列那些可以到达
    y
    不能从
    y
    到达其左侧的节点。因此,第二个DFS能够避免将此类节点
    x
    添加到
    y
    的SCC中,这可能会对您有所帮助