强连通分量的C++代码实现与讲解

发布时间 2023-04-21 09:45:07作者: OIER笔记

以下是强连通分量的C++代码实现以及过程讲解:

假设我们有一个有向图,我们需要找到它的所有强连通分量。

步骤1:首先,我们需要定义一个全局变量用于记录强连通分量的数量。我们可以称之为SCC_COUNT,并将其初始化为0。

int SCC_COUNT = 0;

步骤2:接下来,我们需要定义一个DFS函数,该函数将用于处理每个节点,并查找其所属的强连通分量。该函数的参数包括当前节点的编号,图的邻接表,一个布尔类型的visited数组以记录节点是否已被访问以及一个stack类型的stack数组以记录遍历顺序。

void DFS(int u, vector adj[], bool visited[], stack& st) {
visited[u] = true;
for (int v : adj[u]) {
if (!visited[v]) {
DFS(v, adj, visited, st);
}
}
st.push(u);
}

步骤3:我们接着需要定义一个逆DFS函数,该函数将用于遍历图的逆图,并以相反的遍历顺序查找每个节点的强连通分量。该函数的参数包括当前节点的编号,图的逆邻接表,一个布尔类型的visited数组以记录节点是否已被访问以及一个vector类型的component数组以记录每个节点所属的强连通分量。

void reverseDFS(int u, vector revAdj[], bool visited[], vector& component) {
visited[u] = true;
component.push_back(u);
for (int v : revAdj[u]) {
if (!visited[v])
reverseDFS(v, revAdj, visited, component);
}
}

步骤4:我们现在可以处理我们的强连通分量算法了。将所有节点标记为未访问状态,然后对于每个未访问的节点,我们使用DFS函数进行完整的DFS遍历,并在每次访问节点时将其推到stack中。这样,我们可以确定遍历顺序,并得到一个stack,其中顶部元素表示末尾节点。然后,我们遍历每个节点并反向遍历逆邻接列表,以找到其所属的强连通分量。对于每个节点,我们标记它是否已访问,以防止重复计算。同时,我们使用vector数组来存储组件中的所有节点。在reverseDFS递归完成后,我们会得到一个组件,该组件包含属于该强连通分量的所有节点。我们将增加SCC_COUNT,并将这些节点添加到我们的结果向量中。

vector<vector> getStronglyConnectedComponents(vector adj[], vector revAdj[], int N) {
bool visited[N];
memset(visited, 0, sizeof(visited));

stack<int> st;
for (int i = 0; i < N; i++) {
    if (!visited[i]) {
        DFS(i, adj, visited, st);
    }
}

SCC_COUNT = 0;

vector<vector<int>> scc;
memset(visited, 0, sizeof(visited));

while (!st.empty()) {
    int u = st.top();
    st.pop();

    if (!visited[u]) {
        vector<int> component;
        reverseDFS(u, revAdj, visited, component);
        scc.push_back(component);
        SCC_COUNT++;
    }
}

return scc;

}

完整C++代码实现:

include <bits/stdc++.h>

define endl '\n'

using namespace std;

const int N = 100005;
vector adj[N], revAdj[N];
int SCC_COUNT = 0;

void DFS(int u, vector adj[], bool visited[], stack& st) {
visited[u] = true;
for (int v : adj[u]) {
if (!visited[v]) {
DFS(v, adj, visited, st);
}
}
st.push(u);
}

void reverseDFS(int u, vector revAdj[], bool visited[], vector& component) {
visited[u] = true;
component.push_back(u);
for (int v : revAdj[u]) {
if (!visited[v])
reverseDFS(v, revAdj, visited, component);
}
}

vector<vector > getStronglyConnectedComponents(vector adj[], vector revAdj[], int N) {
bool visited[N];
memset(visited, 0, sizeof(visited));

stack<int> st;
for (int i = 0; i < N; i++) {
    if (!visited[i]) {
        DFS(i, adj, visited, st);
    }
}

SCC_COUNT = 0;

vector<vector<int> > scc;
memset(visited, 0, sizeof(visited));

while (!st.empty()) {
    int u = st.top();
    st.pop();

    if (!visited[u]) {
        vector<int> component;
        reverseDFS(u, revAdj, visited, component);
        scc.push_back(component);
        SCC_COUNT++;
    }
}

return scc;

}

int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);

int n, m;
cin >> n >> m;

for (int i = 0; i < m; i++) {
    int x, y;
    cin >> x >> y;
    adj[x].push_back(y);
    revAdj[y].push_back(x);
}

vector<vector<int> > scc = getStronglyConnectedComponents(adj, revAdj, n);

cout << "Number of Strongly Connected Components: " << SCC_COUNT << endl;

cout << "Strongly Connected Components: " << endl;
for (vector<int>& component : scc) {
    for (int& node : component) {
        cout << node << " ";
    }
    cout << endl;
}

return 0;

}