到目前为止,我已经使用以下算法来查找图的强连通分量。
调用DFS(G)计算每个顶点v的结束时间f [v],按照结束时间的降序排列G的顶点;
计算G的转置GT;
在G上执行另一个DFS,这次在主for循环中我们遍历G的顶点 按f [v];
将DFS林中的每个树的顶点(由第二个DFS形成)作为单独输出 强连通组件。
但我想知道是否有可能在只有一个DFS中找到所有强关联组件。
在这方面的任何帮助都将受到高度赞赏。
答案 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中获得所有连接的组件。