图的割点 --《啊哈!算法》
时间:2022-06-09
本文章向大家介绍图的割点 --《啊哈!算法》,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
这个算法的关键在于:当深度优先遍历访问到顶点u时,假设图中还有顶点v是没有访问过的点,如何判断顶点v在不经过u
的情况下还能回到之前访问任意一个结点?如果从生成树的角度来说,顶点u就是顶点v的的父亲,而之前已经被访问过的顶点
就是祖先。换句话说,如何检测顶点v在不经过父顶点u的情况下还能否回到祖先。我的方法是对顶点v再进行一次深度优先遍历,但此次遍历不允许经过顶点u,看看能否回到祖先,如果不能回到祖先说明顶点u是割点。
low[i]来记录每个顶点在不经过父顶点时,能够回到的最小时间戳。
代码是用邻接矩阵来存储图的,复杂度O(N^2),边的处理就需要O(N^2)。这样写是为了突出割点部分。实际应用改为邻接表来存储,这样复杂度为O(N+M)
#include <bits/stdc++.h>
using namespace std;
const int maxn=505;
int n,m,e[maxn][maxn];
int root,num[maxn],low[maxn],flag[maxn],index;
void dfs(int cur,int father)//割点算法核心 当前结点,父亲结点
{
int child=0,i;//child用来记录在生成树中当前顶点cur儿子的个数
index++;//时间戳加加
num[cur]=index;//当前顶点cur时间戳
low[cur]=index;//初始化最早能访问到的时间戳,当然是自己了
for(int i=1;i<=n;i++)
{
if(e[cur][i]==1)//遍历所有与当前点联通的点
{
if(num[i]==0)//当前点未访问
{
child++;//从生成树的角度来说就是i是cur的儿子
dfs(i,cur);//继续往下深度优先遍历
low[cur]=min(low[cur],low[i]);//更新时间戳(不经过父亲结点能回到的最小时间戳)
if(cur!=root&&low[i]>=num[cur])
flag[cur]=1; //当前结点不是根结点,满足low[i]>=num[cur],cur为割点
if(cur==root&&child>=2)
flag[cur]=1;//当前结点是根节点,则必须有两个儿子才是割点
}
else if(i!=father)//已经访问但是 这个点不是cur的父亲,
//则说明此时的i为cur的祖先,因此需要更新当前结点cur能访问到的最早结点
{
low[cur]=min(low[cur],num[i]);
}
}
}
}
int main()
{
scanf("%d %d",&n,&m);
memset(e,0,sizeof(e));
memset(flag,0,sizeof(flag));
for(int i=0;i<m;i++)
{
int a,b;
scanf("%d %d",&a,&b);
e[a][b]=1;
e[b][a]=1;//建立边
}
root=1;//根节点是1
dfs(1,root);
for(int i=1;i<=n;i++)
{
if(flag[i]==1)
printf("%d ",i);
}
return 0;
}
in 6 7 1 4 1 3 4 2 3 2 2 5 2 6 5 6 out 2
- 决策树案例:基于python的商品购买能力预测系统
- 数据迁移前的准备和系统检查 (r2笔记70天)
- 数据处理的统计学习(scikit-learn教程)
- 机器学习实战,使用朴素贝叶斯来做情感分析
- Python NLTK 处理原始文本
- 通过闪回事务查看数据dml的情况 (r2笔记69天)
- 通过shell和sql结合查找性能sql(r2笔记68天)
- 淘宝的评论归纳是用什么方法做到的?
- Python的机器学习实战:AadBoost
- 通过shell检查分区表中是否含有默认分区(r2笔记87天)
- 利用python爬取人人贷网的数据
- 通过shell脚本查看package的信息(r2笔记86天)
- 通过shell脚本查看procedure的信息(r2笔记85天)
- 支持中文文本数据挖掘的开源项目PyMining
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Linux有限状态机FSM的理解与实现
- Linux下浅谈crond与crontab的命令用法
- centos 7系统下安装Jenkins的步骤详解
- linux tomcat配置https的方法
- Linux 中firewall的使用方法总结
- CentOS 7 安装vsftpd 服务器的具体操作步骤
- 详细介绍通过配置Apache实现404页面替换
- bug分支和feature分支_动力节点Java学院整理
- Linux下Python脚本自启动与定时任务详解
- Linux服务器tomact 8.0启动慢的完美解决方法
- vim学习高级技巧之序列的生成方法详解
- 【LoRa社区网关点亮活动】基于腾讯云IoT Explorer搭建开放的LoRaWAN网络
- 面试官:说一下List排序方法
- GWAS全基因组关联分析流程(BWA+samtools+gatk+Plink+Admixture+Tassel)
- linux中ipset命令的使用方法详解