割点(Articulation Point)

割点(Articulation Point)

在图论中,割点(Articulation Point)是指在一个无向图中,如果删除某个节点及其关联的边会导致图的连通分量数量增加,那么这个节点就被称为割点。换句话说,割点是图中的一个节点,删除它会使图变得不连通或减少连通分量的数量。

性质

  1. 连通性:删除割点会使得图的连通性降低,即原本连通的节点变得不连通。
  2. 无向图:割点的概念主要应用于无向图。
  3. 割点的检测:可以使用Tarjan算法来检测图中的割点。

Tarjan算法检测割点

Tarjan算法是一种深度优先搜索(DFS)算法,用于检测图中的割点和强连通分量。以下是Tarjan算法检测割点的基本步骤:

  1. 初始化

    • 为每个节点设置一个时间戳(dfn)和一个追溯值(low)。
    • 使用一个栈来记录访问的节点。
  2. DFS遍历

    • 从任意一个节点开始进行DFS遍历。
    • 对于每个节点,记录其访问时间戳(dfn)和追溯值(low)。
    • 对于每个节点的邻接节点,如果邻接节点未被访问过,则递归访问,并更新当前节点的追溯值(low)。
    • 如果邻接节点的追溯值(low)大于等于当前节点的时间戳(dfn),则当前节点是割点。
  3. 割点判定

    • 如果 low[v] >= dfn[u],则节点 u 是割点。

代码:

题目

#include<bits/stdc++.h>
#define int long long
using namespace std;

const int N = 2e5 + 10, mod = 998244353;
typedef long long ll;
typedef pair<int, int> PII;

int T;
int dfn[N], low[N], n, m, idx; // dfn: 时间戳, low: 追溯值, n: 节点数, m: 边数, idx: 时间戳计数器
vector<int> g[N]; // 图的邻接表表示
int cut[N]; // 记录节点是否为割点
int ans = 0; // 割点的数量

// Tarjan算法检测割点
void Tarjan(int u, int p) {
    dfn[u] = low[u] = ++idx; // 初始化时间戳和追溯值
    int sz = 0; // 记录子树的数量
    for (auto v : g[u]) {
        if (!dfn[v]) { // 如果节点v未访问过
            Tarjan(v, u); // 递归访问v
            sz++; // 子树数量加1
            low[u] = min(low[u], low[v]); // 更新追溯值
            if (low[v] >= dfn[u]) cut[u] = 1; // 如果v的追溯值大于等于u的时间戳,则u是割点
        } else if (v != p) { // 如果v不是父节点
            low[u] = min(low[u], dfn[v]); // 更新追溯值
        }
    }
    if (p == 0 && sz <= 1) cut[u] = 0; // 如果u是根节点且子树数量小于等于1,则u不是割点
    ans += cut[u]; // 更新割点数量
}

signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n >> m; // 读取节点数和边数
    for (int i = 1; i <= m; i++) {
        int u, v;
        cin >> u >> v; // 读取边
        g[u].push_back(v); // 添加边到邻接表
        g[v].push_back(u); // 无向图,双向添加
    }
    for (int i = 1; i <= n; i++) {
        if (!dfn[i]) Tarjan(i, 0); // 对每个未访问的节点运行Tarjan算法
    }
    cout << ans << endl; // 输出割点的数量
    for (int i = 1; i <= n; i++) {
        if (cut[i]) cout << i << " "; // 输出所有割点
    }
    return 0;
}
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值