[Tarjan系列] Tarjan算法求无向图的桥和割点
RobertTarjan真的是一个传说级的大人物。
他发明的LCT,SplayTree这些数据结构真的给我带来了诸多便利,各种动态图论题都可以用LCT解决。
而且,Tarjan并不只发明了LCT,他对计算机科学做出的贡献真的很多。
这一篇我就来以他名字命名的Tarjan算法可以O(n)求出无向图的割点和桥。
进一步可以求出无向图的DCC( 双连通分量 )。不止无向图,Tarjan算法还可以求出有向图的SCC( 强连通分量 )。
Tarjan算法基于dfs,接下来我们引入几个基本概念。
dfn:时间戳
我们对一张图进行深度优先遍历,根据第一次访问到它的时间顺序给它打上一个标记,这个标记就是时间戳。
搜索树:
在一张无向连通图中选定任意一个节点进行深度优先遍历,每个点仅访问一次。所有发生了递归的边会构成一棵树,我们称其为无向连通图的“搜索树”。
追溯值:
除了时间戳,Tarjan算法还引入了另一个概念:“追溯值” low。
我们用subtree(x)表示搜索树中以x为根的子树,low[x]定义为下列节点的时间戳的最小值:
1. subtree(x)中的节点 2. 通过一条不在搜索树上的边,能够到达subtree(x)中的节点
我们来画一个图理解一下:(方便起见,图中的节点编号就是它的时间戳)
图中红色的边就是这张图的搜索树
那么我们容易得出:subtree(2)={4,3},5可以通过不在搜索树上的边到达subtree(2)。
所以,low[2]=min{dfn[4],dfn[3],dfn[5]},得出low[2]=3。
根据定义来计算low[x]的方法就非常明显了。因为subtree(x)包括x,所以先令low[x]=dfn[x]。
然后遍历从x出发的每一条边(x,y),计算low[x]。
接下来给出无向图的桥和割点判定法则。
无向边(x,y)是桥,当且仅当x在搜索树上的一个子节点y满足low[y]>dfn[x]。
若x不是搜索树的根节点,则x是割点当且仅当搜索树上的一个子节点y满足low[y]>=dfn[x]。
若x是根节点,则x是割点当且仅当搜索树上存在至少两个x的子节点y1,y2满足上式。
桥边有以下性质:
1. 桥一定是搜索树中的边 2. 一个简单环中边都不是桥边
一个环被称为简单环当且仅当其包含的所有点都只在这个环中被经过了一次。
扩展内容:这里给出用dfs求出一个图中所有简单环的代码
int cnt;
void dfs(int u){
dfn[u]=++cnt;
for(int i=head[u];i;i=nxt(i)){
int v=to(i);
if(v==fa[u])continue;
if(!dfn[v])fa[v]=u,dfs(v);
else if(dfn[u]<dfn[v]){
printf("%d",v);
do{
printf(" %d",fa[v]);v=fa[v];
}while(v!=u);
//找完一个环了
putchar('\n');
}
}
}
这个作为扩展内容就不再展开叙述。
下面给出求出无向图中所有的桥的代码:
#include<bits/stdc++.h>
#define N 100010
using namespace std;
inline int read(){
int data=,w=;char ch=;
while(ch!='-' && (ch<''||ch>''))ch=getchar();
if(ch=='-')w=-,ch=getchar();
while(ch>='' && ch<='')data=data*+ch-'',ch=getchar();
return data*w;
}
struct Edge{
int nxt,to;
#define nxt(x) e[x].nxt
#define to(x) e[x].to
}e[N<<];
int dfn[N],low[N],tot=;//储存边的编号,由于要用^1找反向边,从1开始
int bridge[N],head[N];
int n,m,cnt;
void addedge(int f,int t){
nxt(++tot)=head[f];to(tot)=t;head[f]=tot;
}
void tarjan(int x,int in_edge){//in_edge表示递归进入每个节点的边的编号
dfn[x]=low[x]=++cnt;
for(int i=head[x];i;i=nxt(i)){
int y=to(i);
if(!dfn[y]){
tarjan(y,i);
low[x]=min(low[x],low[y]);//在搜索树上的边
if(low[y]>dfn[x])//桥判定法则
bridge[i]=bridge[i^]=;//这条边和它的反向边都是桥
}else if(i!=(in_edge^))
low[x]=min(low[x],dfn[y]);//不在搜索树上的边
}
}
int main(){
n=read();m=read();
for(int i=;i<=m;i++){
int x=read(),y=read();
addedge(x,y);addedge(y,x);
}
for(int i=;i<=n;i++)
if(!dfn[i])tarjan(i,);
for(int i=;i<tot;i+=)
if(bridge[i])
printf("%d %d\n",to(i^),to(i));//输出桥两边的点
}
以上就是求无向图中所有桥的程序了,可以自己画图模拟一下tarjan算法的流程加深理解。
下面给出求无向图中所有割点的程序:
这里需要注意的是,由于割点判定法则是小于等于号,所以不需要考虑父节点和重边的问题,所有dfn[x]都可以用来更新low[x]
#include<bits/stdc++.h>
#define N 100010
using namespace std;
inline int read(){
int data=,w=;char ch=;
while(ch!='-' && (ch<''||ch>''))ch=getchar();
if(ch=='-')w=-,ch=getchar();
while(ch>='' && ch<='')data=data*+ch-'',ch=getchar();
return data*w;
}
struct Edge{
int nxt,to;
#define nxt(x) e[x].nxt
#define to(x) e[x].to
}e[N<<];
int head[N],dfn[N],low[N],rt,tot=,n,m,cnt;
int cut[N];
inline void addedge(int f,int t){
nxt(++tot)=head[f];to(tot)=t;head[f]=tot;
}
void tarjan(int x){
dfn[x]=low[x]=++cnt;
int flag=;
for(int i=head[x];i;i=nxt(i)){
int y=to(i);
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
if(low[y]>=dfn[x]){//就一个割点判断法则没必要解释什么了吧?
flag++;
if(x!=rt||flag>)cut[x]=;
}
}else low[x]=min(low[x],dfn[y]);
}
}
int main(){
n=read();m=read();
for(int i=;i<=m;i++){
int x=read(),y=read();
if(x==y)continue; //自环直接判掉好吧,不多bb
addedge(x,y);addedge(y,x);
}
for(int i=;i<=n;i++)
if(!dfn[i])rt=i,tarjan(i);//无向图不一定连通,对每一个连通块都要跑一发tarjan
for(int i=;i<=n;i++)
if(cut[i])printf("%d ",i);
return ;
}
桥边判定法则和割点判定法则后面会update上,这一篇暂时更到这里,下一篇讲e-DCC和v-DCC的求法
主要是联赛在即,更新尽量多的算法扎实自己基础才要紧些...请多见谅
[Tarjan系列] Tarjan算法求无向图的桥和割点的更多相关文章
- tarjan算法求无向图的桥、边双连通分量并缩点
// tarjan算法求无向图的桥.边双连通分量并缩点 #include<iostream> #include<cstdio> #include<cstring> ...
- Light OJ - 1026 - Critical Links(图论-Tarjan算法求无向图的桥数) - 带详细注释
原题链接 无向连通图中,如果删除某边后,图变成不连通,则称该边为桥. 也可以先用Tajan()进行dfs算出所有点 的low和dfn值,并记录dfs过程中每个 点的父节点:然后再把所有点遍历一遍 ...
- Hdu 4738【tanjan求无向图的桥】割边判定定理 dfn[x] < low[y]
题目: 曹操在长江上建立了一些点,点之间有一些边连着.如果这些点构成的无向图变成了连通图,那么曹操就无敌了.刘备为了防止曹操变得无敌,就打算去摧毁连接曹操的点的桥.但是诸葛亮把所有炸弹都带走了,只留下 ...
- [Tarjan系列] Tarjan算法求无向图的双连通分量
这篇介绍如何用Tarjan算法求Double Connected Component,即双连通分量. 双联通分量包括点双连通分量v-DCC和边连通分量e-DCC. 若一张无向连通图不存在割点,则称它为 ...
- tarjan算法--求无向图的割点和桥
一.基本概念 1.桥:是存在于无向图中的这样的一条边,如果去掉这一条边,那么整张无向图会分为两部分,这样的一条边称为桥无向连通图中,如果删除某边后,图变成不连通,则称该边为桥. 2.割点:无向连通图中 ...
- hdu 4738 Caocao's Bridges 求无向图的桥【Tarjan】
<题目链接> 题目大意: 曹操在长江上建立了一些点,点之间有一些边连着.如果这些点构成的无向图变成了连通图,那么曹操就无敌了.周瑜为了防止曹操变得无敌,就打算去摧毁连接曹操的点的桥.但是诸 ...
- [Tarjan系列] Tarjan算法与有向图的SCC
前面的文章介绍了如何用Tarjan算法计算无向图中的e-DCC和v-DCC以及如何缩点. 本篇文章资料参考:李煜东<算法竞赛进阶指南> 这一篇我们讲如何用Tarjan算法求有向图的SCC( ...
- 蓝桥杯历届试题 危险系数(dfs或者并查集求无向图关于两点的割点个数)
Description 抗日战争时期,冀中平原的地道战曾发挥重要作用. 地道的多个站点间有通道连接,形成了庞大的网络.但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系. 我们来定义一个 ...
- SPF Tarjan算法求无向图割点(关节点)入门题
SPF 题目抽象,给出一个连通图的一些边,求关节点.以及每个关节点分出的连通分量的个数 邻接矩阵只要16ms,而邻接表却要32ms, 花费了大量的时间在加边上. // time 16ms 1 ...
随机推荐
- Docker安装redis3.2
1.拉取redis3.2镜像 2.使用docker images查看拉去下来的镜像 3.运行容器,命令如下 docker run -p : -v $PWD/data:/data -d redis:3. ...
- 关于IC电源管脚去耦电容
原文地址:https://mp.weixin.qq.com/s/0dAyTpAcQWXlYULqCeKgFA 每个集成电路(IC)都必须使用电容将各电源引脚连接到器件上的地,原因有二:防止噪声影响其本 ...
- hTTP的URL编码
使用jdk提供的类完成URL的编解码 public class UrlDemo { public static void main(String[] args) throws Exception { ...
- 阶段5 3.微服务项目【学成在线】_day03 CMS页面管理开发_18-异常处理-不可预知异常处理
框架抛出来的或者一些第三方的组件抛出来的异常.我们根本不知道它所对应的错误代码的信息,所以我们也没有办法给用户返回具体的错误代码和错误信息. 我们先在Map中定义有一些不可预知的异常,定义错误代码和错 ...
- spring中的原型模式
大家好,我原本是神剑山庄的铸剑师,名叫小赵,本来干的好好的,后来一时兴起,睡了三少爷的小姨子,与其一直提心吊胆,干脆来个逃之夭夭. 但是,我也要吃饭的呀,工作也得找,神剑山庄去不得,还有断剑山庄.藏剑 ...
- HBase管理与监控——HMaster或HRegionServer自动停止挂掉
问题描述 HBase在运行一段时间后,会出现以下2种情况: 1.HMaster节点自动挂掉: 通过jps命令,发现HMaster进程没了,只剩下HRegionServer,此时应用还能正常往HBase ...
- Spring Boot中报错org.apache.ibatis.binding.BindingException: Parameter 'XXXX' not found. Available parameters are [0, 1, param1, param2]的解决办法
我这里的报错信息显示: org.apache.ibatis.binding.BindingException: Parameter 'reqUsername' not found. Available ...
- ThreadLocal的简单介绍
ThreadLocal是什么 早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路.使用这个工具类可以很简洁地 ...
- 【ARM-Linux开发】C语言getcwd()函数:取得当前的工作目录
相关函数:get_current_dir_name, getwd, chdir 头文件:#include <unistd.h> 定义函数:char * getcwd(char * buf, ...
- edusoho twig 引入文件功能
在这里不得不提 edusoho twig 模板引擎了 跟smarty 比较类似 不过感觉还是更好一点儿 这里用的标签就只有一个 {% include '路径/文件名' %} 大家在首页做的改动比较多 ...