在一个DFS中查找Di-Graph中的强连接组件

时间:2012-10-23 14:57:17

标签: c++ c algorithm graph

到目前为止,我已经使用以下算法来查找图的强连通分量。

  1. 调用DFS(G)计算每个顶点v的结束时间f [v],按照结束时间的降序排列G的顶点;

  2. 计算G的转置GT;

  3. 在G上执行另一个DFS,这次在主for循环中我们遍历G的顶点 按f [v];

  4. 的降序排列
  5. 将DFS林中的每个树的顶点(由第二个DFS形成)作为单独输出 强连通组件。

  6. 但我想知道是否有可能在只有一个DFS中找到所有强关联组件。

    在这方面的任何帮助都将受到高度赞赏。

2 个答案:

答案 0 :(得分:2)

我在维基百科页面上找到Strongly connected component

  

Kosaraju的算法,Tarjan的算法和基于路径的强大算法   组件算法都能有效地计算强连通性   有向图的组成部分,但Tarjan和基于路径的   算法在实践中受到青睐,因为它们只需要   深度优先搜索而不是两个。

我认为这完全回答了你的问题:)

答案 1 :(得分:2)

查看Steven Skiena的算法设计手册。它在一个DFS中计算SCC。它基于最老的可到达顶点的概念。

在开头将每个顶点的可到达顶点和SCComponent#初始化为自身。

low[i] = i;
scc[i] = -1;

在有向图上执行DFS,您只对后边缘和交叉边缘感兴趣,因为这两条边将告诉您是否遇到后边缘并从另一边进入1个分量。

  int edge_classification(int x, int y)
  {
    if (parent[y] == x) return(TREE);
    if (discovered[y] && !processed[y]) return(BACK);
    if (processed[y] && (entry_time[y]>entry_time[x])) return(FORWARD);
    if (processed[y] && (entry_time[y]<entry_time[x])) return(CROSS);
     printf("Warning: unclassified edge (%d,%d)\n",x,y);
  }

因此,当您遇到这些边时,您可以根据输入时间递归设置可达顶点[]。     if(class == BACK){                 if(entry_time [y]&lt; entry_time [low [x]])                 low [x] = y;     }

if (class == CROSS) 
{
            if (scc[y] == -1)  /* component not yet assigned */
                    if (entry_time[y] < entry_time[ low[x] ] )
                            low[x] = y;
}

每当来自顶点'v'的最低可到达顶点本身时(环可以说,a-> b-> c-> a,a的最低可到达顶点是a),就会发现新的强连通分量。

process_vertex_early(int v)
{
    push(&active,v);
}

顶点的DFS完成后(其邻居的DFS也已完成),检查它的最低可到达顶点:

if (low[v] == v) 
{     /* edge (parent[v],v) cuts off scc */
          pop_component(v);
}

if (entry_time[low[v]] < entry_time[low[parent[v]]])
          low[parent[v]] = low[v];

pop_component(...)只是从堆栈中弹出,直到找到此组件。如果a-> b-> c-> a被扫描,则堆栈将具有(底部) - > b-> c(顶部).. pop直到看到顶点'a'。你得到一个'a'的SCC ..同样你在一个DFS中获得所有连接的组件。