当前位置: 首页 > news >正文

题解:洛谷 P3388 割点

【题目来源】

洛谷:P3388 【模板】割点(割顶) - 洛谷

【题目描述】

给出一个 \(n\) 个点,\(m\) 条边的无向图,求图的割点。

【输入】

第一行输入两个正整数 \(n,m\)

下面 \(m\) 行每行输入两个正整数 \(x,y\) 表示 \(x\)\(y\) 有一条边。

【输出】

第一行输出割点个数。

第二行按照节点编号从小到大输出节点,用空格隔开。

【输入样例】

6 7
1 2
1 3
1 4
2 5
3 5
4 5
5 6

【输出样例】

1
5

【核心思想】

  1. 问题分析:给定一个 \(n\) 个点 \(m\) 条边的无向图,求所有的割点(割顶)。割点是指删除该点后,图的连通分量数量会增加的点。这是一个Tarjan算法问题,关键在于通过DFS遍历计算每个节点的 dfn(时间戳)和 low(能回溯到的最早时间戳),判断节点是否为割点。

  2. 算法选择

    • Tarjan算法:使用DFS遍历图,在 \(O(n + m)\) 时间内找到所有割点
    • 割点判定条件:对于节点 \(x\) 的子节点 \(y\),若 low[y] >= dfn[x],说明 \(y\) 无法通过回边到达 \(x\) 的祖先,\(x\) 是割点
    • 根节点特判:根节点需要有两个或以上子树才是割点
  3. 关键步骤

    • 建图:读取 \(m\) 条无向边,构建邻接表
    • 初始化dfn[] = low[] = 0,时间戳计数器 tim = 0
    • Tarjan DFS
      • 对每个未访问的节点作为根节点调用 tarjan(root)
      • dfn[x] = low[x] = ++tim:初始化时间戳
      • 遍历邻接节点 \(y\)
        • \(y\) 未访问:递归 tarjan(y),更新 low[x] = min(low[x], low[y])
        • low[y] >= dfn[x]\(y\) 无法绕过 \(x\) 到达祖先,\(x\) 可能是割点
        • 子树计数 child++,若 x != root || child > 1 则标记 cut[x] = 1
        • \(y\) 已访问:low[x] = min(low[x], dfn[y])
    • 输出结果:统计并输出所有割点
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n + m)\),每个节点和边只被访问一次
    • 空间复杂度:\(O(n + m)\),邻接表和辅助数组
  5. 割点与Tarjan算法的核心思想

    • 割点定义:删除该点后,图的连通分量数增加,即该点是某些子树的唯一连接点
    • dfn与low数组dfn 记录DFS访问顺序,low 记录通过回边能到达的最早祖先
    • 割点判定原理:若子节点 \(y\)low[y] >= dfn[x],说明 \(y\) 及其子树无法通过回边到达 \(x\) 的祖先,\(x\)\(y\) 子树与图中其他部分的唯一连接点
    • 根节点特判:根节点没有祖先,需要有两个或以上独立子树才是割点
    • 适用于无向图连通性分析、网络关键节点识别、图的分割类问题

【算法标签】

普及plus #强连通分量

【代码详解】

// 引入所有标准库头文件,方便使用各种标准库功能
#include <bits/stdc++.h>// 使用标准命名空间,避免每次使用标准库函数时都需要加 std:: 前缀
using namespace std;// 定义常量 N,表示节点的最大数量,通常用于限制数组和向量的大小
const int N = 20005;// 定义全局变量
int n, m, a, b;  // n: 节点数量,m: 边数量,a, b: 用于读取每条边的两个节点// 定义邻接表 e,用于存储图的边,e[i] 存储与节点 i 相连的所有节点
vector<int> e[N];// 定义数组 dfn 和 low,用于 Tarjan 算法中的深度优先搜索编号和最低可达编号
int dfn[N], low[N];// 定义时间戳 tim,用于记录 DFS 的访问顺序
int tim;// 定义数组 cut,用于标记节点是否为割点,cut[i] = 1 表示节点 i 是割点
int cut[N];// 定义变量 root,用于表示当前 Tarjan 算法处理的根节点
int root;// Tarjan 算法的递归函数,用于寻找图中的割点
// 参数 x 表示当前处理的节点
void tarjan(int x)
{// 设置当前节点 x 的深度优先搜索编号和最低可达编号为当前时间戳,并递增时间戳dfn[x] = low[x] = ++tim;// 初始化子节点计数器 son,用于记录当前节点的子节点数量int son = 0;// 遍历当前节点 x 的所有邻接节点 yfor (int y : e[x]){// 如果邻接节点 y 还没有被访问过(即 dfn[y] 为 0)if (!dfn[y]){// 递归调用 Tarjan 算法处理邻接节点 ytarjan(y);// 更新当前节点 x 的最低可达编号为 dfn[x] 和 low[y] 中的较小值low[x] = min(low[x], low[y]);// 判断当前节点 x 是否为割点// 条件:如果 low[y] >= dfn[x],表示 y 无法通过回边到达 x 的祖先,因此 x 可能是割点if (low[y] >= dfn[x]){son++;  // 增加子节点计数// 判断是否满足割点的条件// 条件1:如果当前节点 x 不是根节点(x != root),或者// 条件2:如果当前节点 x 是根节点且有多个子节点(son > 1)if (x != root || son > 1)cut[x] = 1;  // 标记节点 x 为割点}}// 如果邻接节点 y 已经被访问过,则更新当前节点 x 的最低可达编号为 dfn[x] 和 dfn[y] 中的较小值elselow[x] = min(low[x], dfn[y]);}
}// 主函数,程序的入口点
int main()
{// 从标准输入读取节点数量 n 和边数量 mcin >> n >> m;// 循环读取每条边,构建无向图while (m--){// 读取边的两个节点 a 和 bcin >> a >> b;// 在邻接表 e 中,将节点 a 和节点 b 互相连接,表示无向边e[a].push_back(b);e[b].push_back(a);}// 遍历所有节点,对每个未被访问的节点调用 Tarjan 算法for (root = 1; root <= n; root++)if (!dfn[root])tarjan(root);// 初始化答案变量 ans,用于计数割点的数量int ans = 0;// 遍历所有节点,统计被标记为割点的节点数量for (int i = 1; i <= n; i++)if (cut[i])ans++;// 输出割点的总数量cout << ans << endl;// 输出所有被标记为割点的节点编号for (int i = 1; i <= n; i++)if (cut[i])cout << i << " ";// 输出换行符,以美化输出格式cout << endl;// 程序正常结束,返回 0return 0;
}

【运行结果】

6 7
1 2
1 3
1 4
2 5
3 5
4 5
5 6
1
5
http://www.jsqmd.com/news/1018955/

相关文章:

  • Linux 达梦数据库(DM8)超详细全流程手册(生产级 / 嵌入式 / GIS 开发专属)
  • 3步彻底解决macOS应用卸载残留问题:Pearcleaner如何释放30%磁盘空间
  • 【Zephyr开发系列-7】Zephyr程序调试解析
  • VLE指令集:嵌入式处理器代码密度优化原理与应用
  • 别再走弯路!2026实测靠谱的AI论文平台|避坑版
  • 2026谷歌流量转化操盘手测评榜单|中立选型指南(去营销化) - 品牌2026推荐
  • VLE指令集:嵌入式开发中的代码密度优化与混合编码实践
  • LLM-Mixer:面向多尺度时间序列的混合感知大模型架构
  • 一体化污水处理设备技术解析与合规落地指南 - 奔跑123
  • USB-Disk-Ejector:Windows设备安全弹出终极解决方案,告别繁琐操作!
  • 旧衣回收小程序开发攻略
  • Prompt工程从入门到进阶!基于通义千问实战零样本/少样本/CoT/攻防防范(附完整代码)
  • 打造个人飞行雷达:dump1090 ADS-B信号解码全攻略
  • DataWorks新手避坑指南:ODPS SQL执行报错的8个常见原因与修复方法
  • 武汉四大正规猫犬繁育门店综合测评|朋博猫舍犬舍双店主推,全门店服务详解 + 5 大热犬城市选购指南 - 同城宠物优选基地
  • 2026短信营销降投诉方案:手机号黑名单检测技术选型推荐与落地指南
  • 71
  • 上海本地包包回收门店推荐:5家高评分机构实测,收的顶凭实力居首位 - 奢侈品回收测评
  • 企业微信Java集成终极指南:wecom-sdk 3分钟快速对接实战
  • 金融方向发展,选应用统计还是大数据管理
  • 预算20万网站建设公司怎么选?2026年差异化建站服务商梯队排行,适配专项体验解析 - 资讯报道
  • 2026年粉末灌装机品牌选型指南:实力企业解析与采购参考 - 信息热点
  • I2C中断驱动编程实战:寄存器配置与状态机设计详解
  • 什么是JDK以及JDK都由哪些部分组成呢
  • OSPF区域内路由计算原理与LSA结构分析
  • 计算机毕业设计之校园购物app
  • MSC8251 RapidIO错误检测与处理机制深度解析与实战配置
  • 2026国内MG动画制作公司实力盘点与选型参考 - 品研笔录
  • PowerPC BDM调试器USB-ML-PPCBDM硬件连接、驱动配置与实战指南
  • 2026年AI论文软件全景评测:这5款工具如何重塑学术生产力