定义分析

  • 给定一个无向连通图\(G=(V,E)\)

  • 对于\(x\in Y\),如果删去\(x\)及与\(x\)相连的边后,\(G\)分裂为两个或者两个以上的不连通子图,那么称\(x\)为\(G\)的割点

  • 对于\((x,y)\in E\),如果删去\((x,y)\)后,\(G\)分裂为两个不连通的子图,那么就称\((x,y)\)为\(G\)的桥或者割边

  • 一般无向图(不保证连通)的割点和桥 指的是各个连通块的割点和桥

在这个图中,\(1,6\)号结点为割点,\((1,6),(6,7)\)是桥

概念引入(Tarjan独特概念)

  • 时间戳:对一张无向连通图进行DFS,使每个点只经过一遍,并且按照每个点第一次被访问的时间顺序依次标号(也就是他们的DFS序),这个标号被称为时间戳,记为\(dfs_x\).

  • 搜索树:在时间戳形成的DFS过程中,我们发现所有构成递归的边构成了一棵树,称之为无向连通图的搜索树.

  • 追溯值:设\(subtree(x)\)表示搜索树中以\(x\)为根的子树,节点\(u\)的追溯值我们定义为\(low_u\),定义为一下结点时间戳的最小值.

    1、位于\(subtree(x)\)中的节点.

    2、通过一条不在搜索树上的边,可以到达\(subtree(x)\)的节点.

构建方法(追溯值,时间戳)

  • 第一次访问到一个节点\(x\)的时候,首先我们令\(low_x=dfn_x\).

  • 然后,我们继续考虑与\(x\)相邻的每一条边,如果没有被访问过,那么就递归

    地却访问他们,回溯是更新\(low_x\).

  • 如果\(y\in subtree(x)\),那么\(low_x=min(low_x,low_y)\).

  • 否则\(low_x=min(low_x,dfn_y)\).

割点的判定

  • 如果\(x\)不是搜索树上的根节点,那么\(x\)的割点判定条件为当且仅当搜索树上的一个子节点\(y\)满足
\[dfn_x\leq low_y
\]
  • 解释:(请先理解好追溯值定义)这个公式表示的意思是在\(subtree(y)\)中的点如果不经过\(x\)那么就无法到达比\(x\)更早访问过的点。

  • 特殊情况:如果\(x是根节点\),那么\(x\)是割点当且仅当搜索树上的两个子节点\(y\)满足上述条件时成立,表示这两个子节点无法互相到达

桥的判定

  • 无向边\((x,y)\)是桥,当且仅当\((x,y)\),位于搜索树上,并且在搜索树上\(x\)的一个子节点\(y\)满足
\[dfn_x<low_y
\]
  • 表示从\(subtree(y)\)出发,在不经过\((x,y)\)的前提下,无论是怎么走都无法到达\(x\)或者比\(x\)更早访问过的节点

  • 当然,一个简单环里面的边一定不是桥,因为他是圈圈!!!

  • 不在搜索树上的边至少都位于至少一个环中,因为不在搜索树上的边那么就表示它一定是连接到了已经被搜索过的点,所以当通过那个点的时候一定能在回到它本身,所以一定在至少一个环中

割点,桥判定代码

#include<cstdio>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=1e5+9;
struct node{
int last;
int to;
}e[N*2];
int head[N],vis[N],dfn[N],low[N],cut[N],cnt,poi,tot;
int n,m,root;
void add(int from,int to)
{
e[++cnt].last=head[from];
e[cnt].to=to;
head[from]=cnt;
}
void tarjan(int x)
{
dfn[x]=low[x]=++poi;
int flag=0;//根节点的判断
for(int i=head[x];i;i=e[i].last)
{
int v=e[i].to;
if(!dfn[v])//没有打时间戳说明未被搜索到过
{
tarjan(v);
low[x]=min(low[v],low[x]);
if(low[v]>=dfn[x])
{
flag++;
if(x!=root||flag>1)
{
cut[x]=1;
}
}
}
else low[x]=min(low[x],dfn[v]);
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
if(x==y) continue;
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++)
{
if(!dfn[i])
{
root=i;
tarjan(i);
}
}
for(int i=1;i<=n;i++)
{
if(cut[i]) tot++;
}
cout<<tot<<endl;
for(int i=1;i<=n;i++)
{
if(cut[i]) cout<<i<<" "; //输出割点
}
return 0;
}``` ```void tarjan(int x, int in_edge) //求桥
{
dfn[x] = low[x] = ++num;
for (int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if (!dfn[y]) {
tarjan(y, i);
low[x] = min(low[x], low[y]);
if (low[y] > dfn[x])
bridge[i] = bridge[i ^ 1] = true;
}
else if (i != (in_edge ^ 1))
low[x] = min(low[x], dfn[y]);
}
}

tarjan 复习笔记 割点与桥的更多相关文章

  1. Tarjan无向图的割点和桥(割边)全网详解&算法笔记&通俗易懂

    更好的阅读体验&惊喜&原文链接 感谢@yxc的腿部挂件 大佬,指出本文不够严谨的地方,万分感谢! Tarjan无向图的割点和桥(割边) 导言 在掌握这个算法前,咱们有几个先决条件. [ ...

  2. tarjan复习笔记

    tarjan复习笔记 (关于tarjan读法,优雅一点读塔洋,接地气一点读塔尖) 0. 连通分量 有向图: 强连通分量(SCC)是个啥 就是一张图里面两个点能互相达到,那么这两个点在同一个强连通分量里 ...

  3. 学习笔记--Tarjan算法之割点与桥

    前言 图论中联通性相关问题往往会牵扯到无向图的割点与桥或是下一篇博客会讲的强连通分量,强有力的\(Tarjan\)算法能在\(O(n)\)的时间找到割点与桥 定义 若您是第一次了解\(Tarjan\) ...

  4. Tarjan求无向图割点、桥详解

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

  5. tarjan复习笔记 双连通分量,强连通分量

    声明:图自行参考割点和桥QVQ 双连通分量 如果一个无向连通图\(G=(V,E)\)中不存在割点(相对于这个图),则称它为点双连通图 如果一个无向连通图\(G=(V,E)\)中不存在割边(相对于这个图 ...

  6. 求无向图的割点和桥模板(tarjan)

    一.基本概念 1.桥:若无向连通图的边割集中只有一条边,则称这条边为割边或者桥 (离散书上给出的定义.. 通俗的来说就是无向连通图中的某条边,删除后得到的新图联通分支至少为2(即不连通: 2.割点:若 ...

  7. 割点和桥---Tarjan算法

    使用Tarjan算法求解图的割点和桥. 1.割点 主要的算法结构就是DFS,一个点是割点,当且仅当以下两种情况:         (1)该节点是根节点,且有两棵以上的子树;         (2)该节 ...

  8. Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)【转】【修改】

    一.基本概念: 1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成 ...

  9. (转)Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)

    基本概念: 1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个 ...

随机推荐

  1. java中给某个字段加锁

    private String buildLock(String str) { StringBuilder sb = new StringBuilder(str); String lock = sb.t ...

  2. 利用Comparable接口实现对对象数组的排序

    Arrays 类中的sort方法承诺可以对对象数组进行排序,但是需要对象所属的类实现Comparable接口 任何实现Comparable接口的对象都需要实现该方法 并且在Java SE 5.0之前该 ...

  3. JAVA程序通过JNI调用C/C++库

    java程序如何调用c/c++库中的函数主要分为三个步骤: 1. 加载库文件. System.loadLibrary 2. 找到函数( java函数<----映射---->c函数 ) 3. ...

  4. 多人VNC远程桌面服务配置

    博主前篇博客里面已经讲过VNC的配置,为了方便查看,单独拿出来写一下. (1) 搜索可以用来安装vncserver的软件包: sudo apt-cache search vncserver (2) 安 ...

  5. OneBlog开源博客-详细介绍如何实现freemarker自定义标签

    前言 OneBlog中使用到了springboot + freemarker的技术,同时项目里多个controller中都需要查询一个公有的数据集合,一般做法是直接在每个controller的方法中通 ...

  6. Vs2017编译器提示:不能将“const char *”类型的值分配到“char *”类型的实体

    在项目属性中将语言符合模式改成否即可

  7. java数组基础知识

    数组的定义:int[] array=new array[n];int array[]={, , , ,};定义了数组,JVM就会给其一个空间,数组是应用类型的数据类型,其存储方式是随机存储. 数组的遍 ...

  8. spark-streaming-连接kafka的两种方式

    推荐系统的在线部分往往使用spark-streaming实现,这是一个很重要的环节. 在线流程的实时数据一般是从kafka获取消息到spark streaming spark连接kafka两种方式在面 ...

  9. Sentry(v20.12.1) K8S 云原生架构探索,玩转前/后端监控与事件日志大数据分析,高性能+高可用+可扩展+可伸缩集群部署

    Sentry 算是目前开源界集错误监控,日志打点上报,事件数据实时分析最好用的软件了,没有之一.将它部署到 Kubernetes,再搭配它本身自带的利用 Clickhouse (大数据实时分析引擎)构 ...

  10. Gradle最佳实践

    一.Gradle相比Maven的优势 配置简洁 Maven是用pom.xml管理,引入一个jar包至少5行代码,Gradle只需要一行. 构建速度快 Gradle支持daemon方式运行,启动速度快, ...