Tarjan求割点(割顶) 割边(桥)
割点的定义:
感性理解,所谓割点就是在无向连通图中去掉这个点和所有和这个点有关的边之后,原先连通的块就会相互分离变成至少两个分离的连通块的点。
举个例子: 图中的4号点就是割点,因为去掉4号点和有关边之后连通块{1,2,3} {5} {6}就相互分离了。

图片来自:一篇写的较好的blog:https://www.cnblogs.com/jason2003/p/7603886.html
Tarjan算法求割点:
有好多个Tarjan算法,不要傻傻分不清~~
其实和有向图求强连通分量的Tarjan算法差不多啦,也用到了dfn和low。
因为是无向连通图,所以横向边是没有意义的,(有反向边的存在)。
dfn[u]:u在搜索树中被遍历到的次序号(时间戳)。
low[u]:u或u的子树中的结点经过最多一条后向边能追溯到的最早的树中结点的次序号(dfn),有点懵,先不管他,感性理解就是通过边到达的点的最小时间戳。
割点判断条件:
①:若u为树的树根,那么只要u有两个及以上的子节点,那么只要u点消失,子节点所在的连通块就会分离了。
如果只有一个子节点,那么u消失之后还剩下那个子节点的连通块,仍是一个并不是多个。
②:若u不为树根,v不为u的父结点,当dfn[u]<=low[v]时,u就为割点,由该式子的含义可得,v以及v的子树最多只能到达u结点,
不能到达u的祖先,此时删掉u,那么(v及v的子树)和(u的祖先)就会相互分离了,自然u就是割点。
求割点时若(u,v)为后向边,v不为u的父结点,low[u]=min{low[u],dfn[v]},里面一定要写dfn[v],不能写low[v]。
原因详见:https://www.luogu.org/blog/ztyluogucpp/solution-p3388
割点模板:
L3388 【模板】割点(割顶):https://www.luogu.org/problemnew/show/P3388
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define ll long long
#define maxn 100009
inline ll read()
{
ll x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-') f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+(ll)(ch-'');ch=getchar();}
return x*f;
}
int head[maxn],dfn[maxn],low[maxn],point[maxn];
int n,m,k,ans,cnt,id,tot,root;
struct edge
{
int to,nxt;
}p[maxn<<]; void add(int x,int y)
{
++cnt,p[cnt].to=y,p[cnt].nxt=head[x],head[x]=cnt;
} void Tarjan(int u,int fa)
{
dfn[u]=low[u]=++id;
int child=;
for(int i=head[u];i;i=p[i].nxt)
{
int v=p[i].to;
if(!dfn[v])
{
Tarjan(v,u);
low[u]=min(low[u],low[v]);
if(u!=root&&low[v]>=dfn[u])
point[u]=;
if(u==root&&++child>=)
point[u]=;
}
else
low[u]=min(low[u],dfn[v]);
} }
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n=read(),m=read();
for(int i=;i<=m;i++)
{
int x=read(),y=read();
add(x,y),add(y,x);
}
for(int i=;i<=n;i++)
if(!dfn[i])
root=i,Tarjan(i,i);
for(int i=;i<=n;i++)
if(point[i])
tot++;
printf("%d\n",tot);
for(int i=;i<=n;i++)
if(point[i])
printf("%d ",i);
fclose(stdin);
fclose(stdout);
return ;
}
割边的定义:
和割点的定义类似,只不过是把去掉点以及与点有关的边改成了去掉这条边看是否连通就行啦。
Tarjan算法求割边:
和求割点只有一点点小区别...
因为有可能存在重边的问题,所以要将一条无向边拆为两条编号一样的有向边,用邻接表进行储存,在判断(u,v)是否为后向边的时候要注意判断是树枝边的反向边还是新的一条边。
割边判断条件:
dfn[u]<low[v],不可以取等号,因为取等号意味着v及v的子树能够到达结点u,那么(u,v)这条边自然就不是割边了。
割边模板:
L1656 炸铁路:https://www.luogu.org/problemnew/show/P1656
裸的割边模板,虽然不需要判断重边但是还是加上比较好,再用优先队列维护一下答案就可以了。
判断是否是树枝边的反向边的时候只需要判断vis[i^1]是否等于1就行了,因为是这样判断的,所以在建边的时候cnt必须从1开始,因为0^1=0,并不会得到1这条反向边。
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
#define INF 0x3f3f3f3f
#define maxn 159
#define maxm 5009
inline ll read()
{
ll x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+(ll)(ch-'');ch=getchar();}
return x*f;
}
priority_queue<pair<int,int> >q;
int head[maxn],dfn[maxn],low[maxn];
bool vis[maxm<<];
int n,m,k,ans,tot,id,cnt=;
struct edge
{
int to,nxt;
}p[maxm<<]; void add(int x,int y)
{
p[++cnt]={y,head[x]},head[x]=cnt;
} void Tarjan(int u)
{
dfn[u]=low[u]=++id;
for(int i=head[u];i;i=p[i].nxt)
{
if(vis[i^])
continue;
int v=p[i].to;
vis[i]=;
if(!dfn[v])
{
Tarjan(v);
low[u]=min(low[u],low[v]);
if(dfn[u]<low[v])
q.push(make_pair(-min(u,v),-max(u,v)));
}
else
low[u]=min(low[u],dfn[v]);
}
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n=read(),m=read();
for(int i=;i<=m;i++)
{
int x=read(),y=read();
add(x,y),add(y,x);
}
for(int i=;i<=n;i++)
if(!dfn[i])
Tarjan(i);
while(q.size())
{
printf("%d %d\n",-q.top().first,-q.top().second);
q.pop();
}
fclose(stdin);
fclose(stdout);
return ;
}
Tarjan求割点(割顶) 割边(桥)的更多相关文章
- 洛谷P3388 【模板】割点(割顶)(tarjan求割点)
题目背景 割点 题目描述 给出一个n个点,m条边的无向图,求图的割点. 输入输出格式 输入格式: 第一行输入n,m 下面m行每行输入x,y表示x到y有一条边 输出格式: 第一行输出割点个数 第二行按照 ...
- Tarjan求割点和桥
by szTom 前置知识 邻接表存储及遍历图 tarjan求强连通分量 割点 割点的定义 在一个无向图中,如果有一个顶点集合,删除这个顶点集合以及这个集合中所有顶点相关联的边以后,图的连通分量增多, ...
- tarjan求割点与割边
tarjan求割点与割边 洛谷P3388 [模板]割点(割顶) 割点 解题思路: 求割点和割点数量模版,对于(u,v)如果low[v]>=dfn[u]那么u为割点,特判根结点,若根结点子树有超过 ...
- $割点割顶tarjan$
原题 #include <bits/stdc++.h> using namespace std; typedef long long LL; inline LL read () { LL ...
- tarjan求割点割边的思考
这个文章的思路是按照这里来的.这里讨论的都是无向图.应该有向图也差不多. 1.如何求割点 首先来看求割点.割点必须满足去掉其以后,图被分割.tarjan算法考虑了两个: 根节点如果有两颗及以上子树,它 ...
- UESTC 900 方老师炸弹 --Tarjan求割点及删点后连通分量数
Tarjan算法. 1.若u为根,且度大于1,则为割点 2.若u不为根,如果low[v]>=dfn[u],则u为割点(出现重边时可能导致等号,要判重边) 3.若low[v]>dfn[u], ...
- poj_1144Network(tarjan求割点)
poj_1144Network(tarjan求割点) 标签: tarjan 割点割边模板 题目链接 Network Time Limit: 1000MS Memory Limit: 10000K To ...
- POJ 1144 Network(无向图的割顶和桥模板题)
http://poj.org/problem?id=1144 题意: 给出图,求割点数. 思路: 关于无向图的割顶和桥,这篇博客写的挺不错,有不懂的可以去看一下http://blog.csdn.net ...
- POJ 1144 Network(Tarjan求割点)
Network Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 12707 Accepted: 5835 Descript ...
随机推荐
- django系列3 :创建模型
1创建模型 在我们简单的民意调查应用程序中,我们将创建两个模型:Question和Choice.A Question有问题和出版日期.A Choice有两个字段:选择的文本和投票记录.每个Choice ...
- 【Sql Server】SQL SERVER 收缩日志
事务日志记录着在相关数据库上的操作,同时还存储数据库恢复(recovery)的相关信息. 收缩日志的原因有很多种,有些是考虑空间不足,有些则是应用程序限制导致的. 下面介绍的是在简单模式下,进行收缩操 ...
- JVM调优命令-jhat
jhat JVM Heap Analysis Tool命令是与jmap搭配使用,用来分析jmap生成的dump,jhat内置了一个微型的HTTP/HTML服务器,生成dump的分析结果后,可以在浏览器 ...
- MVCC 能解决幻读吗?
MySQL通过MVCC(解决读写并发问题)和间隙锁(解决写写并发问题)来解决幻读 MySQL InnoDB事务的隔离级别有四级,默认是“可重复读”(REPEATABLE READ). 未提交读(REA ...
- 针对主机CPU idle性能情况需求脚本编写
[环境介绍] 系统环境:Linux + osw + python 2.7.10 [背景描述] 需求:当系统服务器出现性能告警的时候,需要定位具体的时间点来进行有针对性的去查询产生的问题.OSW提供了很 ...
- Javaweb学习笔记——(二十三)——————AJAX、XStream、JSON
AJAX概述 1.什么是AJAX ajax(Asynchronous JavaScript and xml) 翻译成中文就是"异步JavaScript和xml&quo ...
- luogu P5289 [十二省联考2019]皮配
传送门 首先考虑一个正常的dp,设\(f_{i,j,k}\)为前\(i\)个学校,\(j\)人在\(\color{#0000FF}{蓝阵营}\),\(k\)人在\(\color{#654321}{吔} ...
- 使用node.js 脚手架搭建Vue项目
1.安装node.js https://nodejs.org/zh-cn/ 下载安装node.js 在命令行测试 node -v 输出版本号说明安装成功 2.使用npm更新安装cpnm npm ins ...
- (四)Java工程化--Git基础
GIT学习参考:https://git-scm.com/book/zh/v2 常见命令 git init 初始化项目 git add *.java 添加文件到git版本控制(.java后缀的全部文件) ...
- Python学习笔记-EXCEL操作
环境Python3 创建EXCEL,覆盖性创建 #conding=utf-8 import xlwt def BuildExcel(ExcelName,SheetName,TitleList,Data ...