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算法求无向图的桥和割点的更多相关文章

  1. tarjan算法求无向图的桥、边双连通分量并缩点

    // tarjan算法求无向图的桥.边双连通分量并缩点 #include<iostream> #include<cstdio> #include<cstring> ...

  2. Light OJ - 1026 - Critical Links(图论-Tarjan算法求无向图的桥数) - 带详细注释

     原题链接   无向连通图中,如果删除某边后,图变成不连通,则称该边为桥. 也可以先用Tajan()进行dfs算出所有点 的low和dfn值,并记录dfs过程中每个 点的父节点:然后再把所有点遍历一遍 ...

  3. Hdu 4738【tanjan求无向图的桥】割边判定定理 dfn[x] < low[y]

    题目: 曹操在长江上建立了一些点,点之间有一些边连着.如果这些点构成的无向图变成了连通图,那么曹操就无敌了.刘备为了防止曹操变得无敌,就打算去摧毁连接曹操的点的桥.但是诸葛亮把所有炸弹都带走了,只留下 ...

  4. [Tarjan系列] Tarjan算法求无向图的双连通分量

    这篇介绍如何用Tarjan算法求Double Connected Component,即双连通分量. 双联通分量包括点双连通分量v-DCC和边连通分量e-DCC. 若一张无向连通图不存在割点,则称它为 ...

  5. tarjan算法--求无向图的割点和桥

    一.基本概念 1.桥:是存在于无向图中的这样的一条边,如果去掉这一条边,那么整张无向图会分为两部分,这样的一条边称为桥无向连通图中,如果删除某边后,图变成不连通,则称该边为桥. 2.割点:无向连通图中 ...

  6. hdu 4738 Caocao's Bridges 求无向图的桥【Tarjan】

    <题目链接> 题目大意: 曹操在长江上建立了一些点,点之间有一些边连着.如果这些点构成的无向图变成了连通图,那么曹操就无敌了.周瑜为了防止曹操变得无敌,就打算去摧毁连接曹操的点的桥.但是诸 ...

  7. [Tarjan系列] Tarjan算法与有向图的SCC

    前面的文章介绍了如何用Tarjan算法计算无向图中的e-DCC和v-DCC以及如何缩点. 本篇文章资料参考:李煜东<算法竞赛进阶指南> 这一篇我们讲如何用Tarjan算法求有向图的SCC( ...

  8. 蓝桥杯历届试题 危险系数(dfs或者并查集求无向图关于两点的割点个数)

    Description 抗日战争时期,冀中平原的地道战曾发挥重要作用. 地道的多个站点间有通道连接,形成了庞大的网络.但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系. 我们来定义一个 ...

  9. SPF Tarjan算法求无向图割点(关节点)入门题

    SPF 题目抽象,给出一个连通图的一些边,求关节点.以及每个关节点分出的连通分量的个数 邻接矩阵只要16ms,而邻接表却要32ms,  花费了大量的时间在加边上. //   time  16ms 1 ...

随机推荐

  1. pwn学习日记Day12 《程序员的自我修养》读书笔记

    目标文件里有什么 ELF各段 代码段 text 数据段 data bss段 只读数据段 rodata 注释信息段 comment 堆栈提示段 .note.GNU-stack comment 存放编译器 ...

  2. Qt 线程基础(QThread、QtConcurrent等) 2

    使用线程 基本上有种使用线程的场合: 通过利用处理器的多个核使处理速度更快. 为保持GUI线程或其他高实时性线程的响应,将耗时的操作或阻塞的调用移到其他线程. 何时使用其他技术替代线程 开发人员使用线 ...

  3. Android5.0以下drawable tag vector错误的解决办法(转发)

    Android5.0以下drawable tag vector错误的解决办法 在Androi 5.0以下的设备可能会报这样的错误: Caused by: org.xmlpull.v1.XmlPullP ...

  4. JPEG Image Super-Resolution via Deep Residual Network

    基于深度残差网络的JPEG图像超分辨率 JPEG Image Super-Resolution via Deep Residual Network PDF https://www.researchga ...

  5. 数据分析 - sql 业务相关练习题

    数据库    userinfo , orderinfo 表 两个 userId 彼此对应 题目 解题 不同月份的下单人数 用户在同一个月份会下多个单,这里进行去重 未支付的脏数据去除 统计用户三月份的 ...

  6. Spring事务管理5-----声明式事务管理(3)

    声明式事务管理  基于注解 在配置文件中需要开启注解驱动<tx:annotation-driven transaction-manager="transactionManager&qu ...

  7. Salesforce LWC学习(九) Quick Action in LWC

    我们在lightning开发中,quick action是一个常用的功能,很可惜的是,lwc目前还不支持单独的custom quick action操作,只能嵌套在aura中使用才能发挥作用. 官方也 ...

  8. windows进入指定目录

    1.进入cmd 2.输入盘符比如:E: 3.切换目录 cd E:\progect\Firstdjango 实例:

  9. antd二级联动异步加载

    /** * Created by Admin on 2016/9/19. * 批量导入 */ import React, {Component, PropTypes} from "react ...

  10. 解决 nginx 单点问题的方案【h】

    一.问题域 nginx.lvs.keepalived.f5.DNS轮询,每每提到这些技术,往往讨论的是接入层的这样几个问题: 1)可用性:任何一台机器挂了,服务受不受影响 2)扩展性:能否通过增加机器 ...