图论(强联通分量)

在图论中,特别是在讨论有向图(Directed Graph)时,我们常常需要了解图的结构特性,比如强联通分量(Strongly Connected Components, SCC)。了解强联通分量中的各种边对于理解图的整体结构以及某些算法(如Tarjan's算法或Kosaraju's算法)是非常重要的。以下是对强联通分量及其边类型的解释:

强联通分量(SCC)

强联通分量是一个子图,其中每对顶点之间都有路径相互可达。换句话说,一个强联通分量内的任意两个顶点 u 和 v 都满足 u 到 v 和 v 到 u 之间存在路径。

边的分类

板子如下

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
vector<int> e[N];       // 存储图的邻接表
int dfn[N], low[N];     // 存储每个节点的时间戳和最小到达时间
bool ins[N];            // 标记节点是否在栈中
int idx, bel[N], cnt;   // 时间戳、节点所属的强联通分量编号、强联通分量计数
stack<int> stk;         // 用于 Tarjan 算法的栈
vector<vector<int>> scc;// 存储所有的强联通分量
int n, m;               // 节点数和边数

void dfs(int u) {
    dfn[u] = low[u] = ++idx; // 初始化时间戳
    ins[u] = true;           // 标记节点在栈中
    stk.push(u);             // 将节点压入栈中

    for (auto v : e[u]) {    // 遍历节点 u 的所有邻接点 v
        if (!dfn[v]) {       // 如果节点 v 尚未访问
            dfs(v);          // 递归访问节点 v
            low[u] = min(low[u], low[v]); // 更新节点 u 的最小到达时间
        } else if (ins[v]) { // 如果节点 v 在栈中
            low[u] = min(low[u], dfn[v]); // 更新节点 u 的最小到达时间
        }
    }

    if (dfn[u] == low[u]) {  // 如果节点 u 是强联通分量的根节点
        vector<int> c;       // 创建一个新的强联通分量
        ++cnt;
        while (1) {
            int v = stk.top(); // 弹出栈顶节点
            c.push_back(v);    // 将节点添加到当前强联通分量中
            ins[v] = false;    // 标记节点不在栈中
            bel[v] = cnt;      // 标记节点所属的强联通分量编号
            stk.pop();         // 弹出栈顶节点
            if (u == v) break; // 如果节点 u 是栈顶节点,结束循环
        }
        sort(c.begin(), c.end()); // 对强联通分量内的节点排序
        scc.push_back(c);         // 将强联通分量添加到结果中
    }
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int u, v;
        cin >> u >> v;
        e[u].push_back(v); // 构建邻接表
    }

    for (int i = 1; i <= n; i++) {
        if (!dfn[i]) dfs(i); // 对每个未访问的节点进行 DFS
    }

    sort(scc.begin(), scc.end()); // 对所有的强联通分量排序
    cout << cnt << endl;          // 输出强联通分量的数量
    for (auto c : scc) {          // 输出每个强联通分量
        for (auto u : c) {
            cout << u << " ";
        }
        cout << endl;
    }
    return 0;
}

题目链接 洛谷 B3609

参考文献scc

相关推荐
铃煦2 小时前
《算法笔记》3.3小节——入门模拟->图形输出
笔记·算法·图论
小林熬夜学编程6 小时前
【高阶数据结构】第二弹---图的深度解析:从基本概念到邻接矩阵的存储与操作
c语言·数据结构·c++·算法·深度优先·图论
一只码代码的章鱼2 天前
数据结构与算法-图论-复习2(差分约束,强连通分量,二分图,LCA,拓扑排序,欧拉路径和欧拉回路)
数据结构·算法·图论
qq_433554542 天前
C++ 蓝桥云课代码练习
c++·算法·图论
一只码代码的章鱼2 天前
数据结构与算法-图论-复习1(单源最短路,全源最短路,最小生成树)
c++·算法·图论
Joe_Wang52 天前
[leetcode]1786. 从第一个节点出发到最后一个节点的受限路径数(Dijkstra+记忆化搜索/dp)
算法·leetcode·图论
WG_173 天前
图论:单源最短路(BF算法+迪杰斯特拉算法+spfa算法)
算法·图论
2301_764441333 天前
基于TRIZ创新方法论的九屏法分析系统
数学建模·图论
蒙奇D索大3 天前
【数据结构】邻接矩阵完全指南:原理、实现与稠密图优化技巧
c语言·数据结构·考研·图论·改行学it
牛奶咖啡.8543 天前
树和图论(详细整理,简单易懂!)
数据结构·c++·算法·深度优先·图论