【问题标题】:Finding the number of strongly connected components查找强连接组件的数量
【发布时间】: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/ 的这个。

步骤如下:

  1. 创建一个空栈“S”并对图进行 DFS 遍历。在DFS遍历中,对一个顶点的相邻顶点调用递归DFS后,将该顶点压入栈中。在上图中,如果我们从顶点 0 开始 DFS,我们在堆栈中得到的顶点为 1、2、4、3、0。

  2. 反转所有弧的方向以获得转置图。

  3. 当 S 不为空时,从 S 中逐个弹出一个顶点。让弹出的顶点为“v”。以 v 为源,做 DFS(调用 DFSUtil(v))。从 v 开始的 DFS 打印 v 的强连通分量。在上面的示例中,我们按照 0、3、4、2、1 的顺序处理顶点(从堆栈中逐个弹出)。

我已经花了很多时间阅读它,但我仍然不了解堆栈背后的逻辑以及节点的完成时间。但是,我认为这种方法与我的方法非常相似,并且我遗漏了一些东西.如果你能帮助我,我会很高兴!

【问题讨论】:

    标签: c++ arrays algorithm recursion graph


    【解决方案1】:

    设 v 是最后一个要完成的节点。在原始图中可以到达 v 的每个节点(因此 v 可以在转置中到达)都在 v 的强分量中。为什么?相反假设x是一个可以到达v的节点,但是v不能到达x。当我们启动 x 时,节点 v 当时不能在堆栈上,因为这意味着到 x 的路径。在我们至少启动 x 可以到达的每个节点之前,我们不能完成 x,所以如果 v 在 x 之前开始,它已经完成(因为不在堆栈上),如果 v 在 x 之后开始,它在 x 之前完成(因为它在堆栈上比 x 高)。矛盾。这个论点延伸到正确性证明。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-25
      • 2022-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多