割点(tarjan算法)
文章目录
- 割点(无向图).
- 总结:
- 割点算法实现模拟
- 题解
- 思考
- 再来一题
割点(无向图).
P3388 【模板】割点(割顶)题目链接:洛谷
tarjan遍历过程视频链接
总结:
1.图用dfs的遍历。dfs对图,就会形成树 (写dfs代码时刻要有"栈"的思想)
2.Tarjan算法求非强连通图,主要用到了两个数组,dfn和low数组。
3.在dfs中如何加东西:
dfs(i)后面语句怎么写?每次dfs完成后,就是对前面的影响,
像栈一样。
4.无向图实际是 在无向树的基础上节点添加边。
连通图定义:
在无向图中,一个连通图中任意两点均可到达,称为连通图。
割点的定义:
在一个无向图里,去掉一个顶点,及其去掉该点的所有边,剩下的图
不连通,那么这个点就是个割点。
割边的定义: (不会不会,以后再补 。)
在一个无向图里,去掉一条边,图就不连通了。
举个栗子:下图的无向图的割点为:0,3。
割点算法实现模拟
ps:以下两图来自上文视频链接截下来的图。
在下图 上面数字dfn数组,下面数字low数组。
用了一个栈更好理解。
其中满足low[u]=dfn[u],退栈到u.
dfn中是时间戳是,1-2-3-4
然后回退到2 , 2-5
再回退到1, 1到6.
最后回退到1.结束。
强连通分量怎么就有了呢?
在退栈2时,进栈5,判断1时,low[5]=dfn[1];
之后在5中退出。
有个5-1,形成了一个1-2-5-1的环,这不就成了一个强连通分量了。
之后就是这么执行。
下面图举例(方便理解后续的代码): 我画成树的样子,再在节点随意连,就成了无向图。
1号是该的根节点 :那么子节点是两个, 就不是三个了?
为什么呢?
原因是: 我们在遍历的时候深度搜索,搜到3时,3就搜到4,4被标记了,退回到1节点,4节点已经标记了,1节点就不会对4搜。
所以1节点的子节点是2个。
所以只要根节点的子节点有两个及以上,根节点就是割点。(这里的子节点要细心些)。
题解
样例输入:
上图。
题解代码如下
代码如下:
割点针对无向图!!
#include<iostream>
#include<vector>
#include<set>
using namespace std;
int read(){int s = 0, f = 1; char ch = getchar();while(!isdigit(ch)){if(ch == '-') f = -1;ch = getchar();}while(isdigit(ch)) s = (s << 3) + (s << 1) + (ch ^ 48), ch = getchar();return s * f;
}const int maxn=2e5+3;
int low[maxn],dfn[maxn]; //dfn:"时间戳"
int visit[maxn]; //点的有无访问
int index;
vector<int> a[maxn]; //邻接表
int fa[maxn]; //
set<int> s;
inline void tarjan(int u){int sum=0;visit[u]=1; dfn[u]=low[u]=++index;for(int i=0;i<a[u].size();i++){int v=a[u][i]; //u到v。if(!visit[v]){fa[v]=u; // 父亲节点用来判断起始点sum++;tarjan(v);//u后面的dfs完成了,执行下面语句时在v顶点要做的事都完成了//现在开始完成u的事,根据v的事完成u的事。low[u]=min(low[u],low[v]);//先把起始点排除.if(fa[u]!=u&&low[v]>=dfn[u]) s.insert(u);} else //if(v!=fa[u]) low[u]=min(low[u],dfn[v]);//dfn[v] 会更好些,有点像能唯一确定他组成一个环的先祖吧//low[v] 写起也怪怪的}//根特判定的原因,根就没先祖了,也就用不了low,dfn判定了。//判断是无割点:子节点两个及以上就是割点。if(fa[u]==u&&sum>=2) s.insert(u);
}
int main (){int n,m;n=read();m=read();int u,v;for(int i=1;i<=m;i++){u=read();v=read();a[u].push_back(v);a[v].push_back(u);}for(int i=1;i<=n;i++){if(!visit[i]){fa[i]=i;//父节点赋初值tarjan(i);index=0;}}cout<<s.size()<<endl;for(set<int>::iterator i=s.begin();i!=s.end();i++){cout<<*i<<" ";}return 0;
}
思考
思考一下没s.insert(u),u会不会被重复的添加呢?
没错,当然会重复咯,不然为啥用set集合呢!,是吧 。
改一下tarjan函数
如下:
那就用ans数组记录下每个割点加了几次。
int ans[maxn];
inline void tarjan(int u){int sum=0;int num=0;visit[u]=1;dfn[u]=low[u]=++index;for(int i=0;i<a[u].size();i++){int v=a[u][i];if(!visit[v]){fa[v]=u;sum++;tarjan(v);low[u]=min(low[u],low[v]);if(low[v]>=dfn[u]) {num++;s.insert(u);//cout<<u<<"end"<<endl;}} else //if(v!=fa[u]) low[u]=min(low[u],dfn[v]);}//if(fa[u]==u&&sum>=2) {num++;s.insert(u);}if(fa[u]!=u) num++;//if(u==1) cout<<num<<endl;ans[u]=num;
}
ans数组结果如下 2 1 2 2 1 2
咦!!!!细心的你发现了,咋就1加了两次呢???
原来顶点1是树的根呀(dfs嘛,就是图的遍历,那就树咯),1都是根了,就没有父节点。low[1]=dfn[1]=1; 所以会加一次。
这就是为啥在题解代码里会有对根节点的特判。
那么根节点怎么才能是割点呢。问到点子上了。
再来一题
2020小米选拔赛第一场D题:Router Mesh
题意:
无向图n点m边
删除任意一点后,有多少个连通图
思路:
首先得知道图不一定是连通的喔。就会牵扯到有好几个连通图。
上文也讲到了ans数组。
嗯哼,派上用场啦..................
删除一点,那他的所有边也会被删掉。那会增加几个连通图呢??
那不得增加ans[i]个咯。
题解代码如下:
#include<iostream>
#include<vector>
#include<set>
using namespace std;
int read(){int s = 0, f = 1; char ch = getchar();while(!isdigit(ch)){if(ch == '-') f = -1;ch = getchar();}while(isdigit(ch)) s = (s << 3) + (s << 1) + (ch ^ 48), ch = getchar();return s * f;
}
const int maxn=4e5+3;
int low[maxn],dfn[maxn];
int visit[maxn];
int index;
vector<int> a[maxn];
int fa[maxn];
set<int> s;
int ans[maxn];
inline void tarjan(int u){int sum=0;int num=0;visit[u]=1;dfn[u]=low[u]=++index;for(int i=0;i<a[u].size();i++){int v=a[u][i];if(!visit[v]){//删去了对根节点的特判,根节点会进入s集合里,如果他不是割点就只进一次。fa[v]=u;sum++;tarjan(v);low[u]=min(low[u],low[v]);if(low[v]>=dfn[u]) {num++;s.insert(u);}} else //if(v!=fa[u]) low[u]=min(low[u],dfn[v]);}//if(fa[u]==u&&sum>=2) {num++;s.insert(u);}//为啥要在这样还要num++呢,嗯。。。玄学。if(fa[u]!=u) num++;//if(u==1) cout<<num<<endl;ans[u]=num;
}
int main (){int n,m;n=read();m=read();int u,v;for(int i=1;i<=m;i++){u=read();v=read();a[u].push_back(v);a[v].push_back(u);}int num=0;for(int i=1;i<=n;i++){if(!visit[i]){num++;fa[i]=i;tarjan(i);index=0;}}/*cout<<s.size()<<endl;for(set<int>::iterator i=s.begin();i!=s.end();i++){cout<<*i<<" ";}*///cout<<num<<endl;for(int i=1;i<=n;i++){//在这里ans[i]减了1 //对应了这条代码if(fa[u]!=u) num++;//也就是根节点不加,非根节点要加1。cout<<ans[i]-1+num<<" ";}return 0;
}
割点(tarjan算法)相关推荐
- POJ 2117 Electricity 割点 Tarjan算法
[题意] 选择去掉无向图中的某个点,使得无向图连通分支数最大,输出这个最大数. 有三种情况: 1.无向图无边时,最大数=点数-1: 2.无向图有边并不存在割点时,最大数=原图连通分支数-1 3.无向图 ...
- 洛谷 P3388 【模板】割点(割顶) 根+非根+dfn[]+low[]+不一样的Tarjan算法
洛谷 P3388 [模板]割点(割顶) 根+非根+dfn[]+low[]+不一样的Tarjan算法 Tarjan算法,详见https://blog.csdn.net/mrcrack/article ...
- Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)...
转载自:http://hi.baidu.com/lydrainbowcat/blog/item/2194090a96bbed2db1351de8.html 基本概念: 1.割点:若删掉某点后,原连通图 ...
- tarjan算法与无向图的连通性(割点,桥,双连通分量,缩点)
基本概念 给定无向连通图G = (V, E) 割点: 对于x∈V,从图中删去节点x以及所有与x关联的边之后,G分裂为两个或两个以上不相连的子图,则称x为割点 割边(桥) 若对于e∈E,从图中删去边e之 ...
- 海亮DAY8 关于Tarjan算法用于割点割边相关感受
Tarjan 简介 Tarjan算法在求割点,割边,连通分量方面及其高效,在军事,交通,设计等方面有重要作用. 由于Tarjan算法思想并不难懂,在此不放上Tarjan算法的具体介绍. [Usaco2 ...
- 超详细Tarjan算法总结,求强连通分量,割点,割边,有重边的割边
Tarjan是一个人,他一身中发明了很多算法,就这几个算法最为出名. 1.求有向图的强连通分量,那么什么是强连通分量呢,就是一个顶点集合,任意两个顶点间都可以互相到达.一个顶点也是强联通分量如果图中任 ...
- tarjan算法 割点割边强联通 算法讲解模板 自用整理
很早就学过tarjan算法(割点割边与强联通)了,但是因为久不用老是忘,也有收藏过几篇不错的博客,但是每次需要时都要翻出那几篇太麻烦了,所以自己开篇记录方便自己的复习.图片和部分文字来源自其他博客,文 ...
- tarjan算法 (割点和桥)
最近刚学习了tarjan算法,发一篇博客写一下自己的心得和理解. 在了解割点和桥之前,我们先理解什么是双连通. 双连通和强连通分别是应用于无向图和有向图中的,那么在学习双连通之前,请自行学习求强连通分 ...
- tarjan算法求无向图的割点和桥
tarjan算法求无向图的割点与桥 一篇tarjan算法求割点与桥的完整的解释,写的真的好认真 以下代码来自kuangbin的模板 4.5 图的割点.桥和双连通分支的基本概念 [点连通度与边连通度] ...
- 20 求图的割点和割边—Tarjan算法
1 图的割点 问题描述 去掉2号城市,这样剩下的城市之间就不能两两相互到达.例如4号城市不能到5号城市,6号城市也不能到达1号城市等等. 下面将问题抽象化.在一个无向连通图中,如果删除某个顶点后,图不 ...
最新文章
- Mysqldump参数大全
- CoTNet-重磅开源!京东AI Research提出新的主干网络CoTNet,在CVPR上获得开放域图像识别竞赛冠军
- asp.net mvc5编程实战_深圳荷坳车铣复合编程培训cnc数控编程技术
- Cpp 11 / override 和 final 区别
- 来不及想标题了,我要去打包收藏了 | 本周值得读
- 利用RMAN转移裸设备到文件系统
- 字符串匹配——枚举法
- ES6 变量的6种方式
- 分而治之:Oracle 18c 及 12.2 分区新特性的 N 种优化实践(含PPT)
- 百万数据查询优化技巧三十则
- 聊聊eureka的preferSameZoneEureka参数
- 深挖AI价值与温度,AETA地震预测AI算法大赛开启
- 【Java】SpringBoot后端格式转换:把PPT转成PDF
- 计算机-磁盘管理不能删除,关于win10系统磁盘管理磁盘右键菜单中只有“帮助”删除方法...
- 2021-08-25 Android studio 编译提示Version 28 (intended for Android Pie and below) is the last version of
- html表格图片垂直居中 css,利用Display: table;实现img图片垂直居中
- 少儿编程scratch如何快速上手?
- 软件测试中文电子版姚静_软件测试[(美)ron patton]读书笔记
- MySQL六十六问——面试复习必备
- 使用原生开发高仿瑞幸小程序(一):使用 Vant 组件库和配置多页面