【发布时间】:2021-06-17 06:07:16
【问题描述】:
我编写了这段代码来查找 SCC(强连通分量)的数量:
#include <iostream>
#include <vector>
using namespace std;
int n , m;
vector<vector<int>>G(101) , GT(101);
void read()
{
//n = number of nodes , m = number of edges.
cin>>n>>m;
for (int i = 0 ; i < m ; i++)
{
int a , b;
cin>>a>>b;
G[a].push_back(b);
GT[b].push_back(a);
}
}
void DFS_G(int node , vector<int>&V)
{
V[node] = 1;
for (int x : G[node])
{
if (!V[x])
DFS_G(x , V);
}
}
void DFS_GT(int node , vector<int>&V)
{
V[node] = 1;
for (int x : GT[node])
{
if (!V[x])
DFS_GT(x , V);
}
}
int main()
{
//G-graph
//GT-reversed graph
int SCC = 0;
read();
vector<int>component(101 , 0);
vector<int>reachedG(101) , reachedGT(101);//will keep nodes reached from x in G and in GT
for (int i = 1 ; i <= n ; i++)
{
if (!component[i])
{
component[i] = 1;
for(int j = 1 ; j <= n ; j++)
{
reachedG[j] = reachedGT[j] = 0;
}
DFS_G(i , reachedG);
DFS_GT(i , reachedGT);
for (int j = 1 ; j <= n ; j++)
{
if (reachedG[j] == 1 && reachedGT[j] == 1)
{
component[j] = 1;
}
}
SCC++;
}
}
cout<<SCC;
return 0;
}
假设您在节点 X。首先我们从 X 进行 DFS,并找到我们可以从它到达的节点。我们在到达 G 向量中将它们标记为已到达。您可能知道,通过反转图然后 DFS从 x 开始,您将遇到的节点实际上是可以到达 XI 的节点,将它们保持在到达GT 中。所以这两个向量之间的交集实际上是我们的节点 X 所在的 SCC。但是,正如我在互联网上看到的那样,这是这不是 Kosaraju 算法的最佳实现。更有效的是来自https://www.geeksforgeeks.org/strongly-connected-components/ 的这个。
步骤如下:
-
创建一个空栈“S”并对图进行 DFS 遍历。在DFS遍历中,对一个顶点的相邻顶点调用递归DFS后,将该顶点压入栈中。在上图中,如果我们从顶点 0 开始 DFS,我们在堆栈中得到的顶点为 1、2、4、3、0。
-
反转所有弧的方向以获得转置图。
-
当 S 不为空时,从 S 中逐个弹出一个顶点。让弹出的顶点为“v”。以 v 为源,做 DFS(调用 DFSUtil(v))。从 v 开始的 DFS 打印 v 的强连通分量。在上面的示例中,我们按照 0、3、4、2、1 的顺序处理顶点(从堆栈中逐个弹出)。
我已经花了很多时间阅读它,但我仍然不了解堆栈背后的逻辑以及节点的完成时间。但是,我认为这种方法与我的方法非常相似,并且我遗漏了一些东西.如果你能帮助我,我会很高兴!
【问题讨论】:
标签: c++ arrays algorithm recursion graph