Tarjan-割点&桥&双连通
$Tarjan$求割点
感觉图论是个好神奇的东西啊,有各种奇奇怪怪的算法,而且非常巧妙。
周末之前说好回来之后进行一下学术交流,于是wzx就教了$Tarjan$,在这里我一定要说:
wzx AK IOI!
Tarjan发明了很多算法,而且还都叫一个名字,所以说只好用用途来区分它们。
闲聊时间结束。
首先,什么是割点呢?在一个无向图中,如果有一个顶点,删除这个顶点以及所有相关联的边以后,图的连通分量增多,就称这个点为割点。
首先找一个点作为根进行搜索,把图按照$dfs$的方法组织成一棵搜索树,树上的边一定都是图上的边,称为树边,而图上其余的边则为非树边(回边)。
如果一个点不能通过非树边而回到比他树上的父亲的$dfs$序更小的点,那么如果把它树上的父亲删掉,它就不能通过其他方法与图的其他部分联通,它的父亲就是一个割点。多么神奇啊!对于根节点,我们可以发现,如果它有不止一个的子树,那它就是割点了。看代码:
割点:https://www.luogu.org/problemnew/show/P3388
void dfs(int x,int roo,int Dad)
{
id[x]=low[x]=++cnt;
int j,cnts=;
for (R i=firs[x];i;i=g[i].nex)
{
j=g[i].too;
if(!id[j])
{
dfs(j,roo,x);
low[x]=min(low[x],low[j]);
if(x==roo) cnts++;
if(low[j]>=id[x]&&x!=roo) f[x]=;
}
else
{
if(j!=Dad) low[x]=min(low[x],low[j]);
}
}
if(x==roo&&cnts>=) f[x]=;
}
Tarjan求割点
这里有一句话还是比较重要的:
1 if(j!=Dad) low[x]=min(low[x],low[j]);
是防止重复走树边,其实也可以改成 $low[x]=min(low[x],id[j])$,这样更新出来的$low$可能不是真正的$low$,但是因为儿子到父亲的路径上不会再有别的点,所以这样也能保证正确性。
割点的理论知识似乎就到此为止了,现在还是看几道题比较好。
[POI2008]BLO-Blockade:https://www.luogu.org/problemnew/show/P3469
题意概述:在一个无向图中删去一个点后,还有多少个有序的(x,y)的点对本可以联通但是现在不能联通了?输出删除每一个点之后的答案。
这道题还是挺妙的,不算是板子题,有一点点思维含量,这样的题最适合入门新算法啦。
如果一个点不是割点,那么损失的点对只有与它直接相连的点;如果一个点是割点,那么割掉它之后图就分成了一些小块,在每个小块内仍是$size*(size-1)$;这么一说感觉也没啥思维难度啊...
# include <cstdio>
# include <iostream>
# define R register int using namespace std; const int maxn=;
const int maxm=;
int cnt=,h=,n,m,x,y,firs[maxn],f[maxn],id[maxn],low[maxn];
long long ans[maxn],siz[maxn];
struct edge
{
int too,nex;
}g[maxm<<]; void add(int x,int y)
{
g[++h].too=y;
g[h].nex=firs[x];
firs[x]=h;
} int read()
{
int x=;
char c=getchar();
while (!isdigit(c))
c=getchar();
while (isdigit(c))
{
x=(x<<)+(x<<)+(c^);
c=getchar();
}
return x;
} void dfs(int x,int roo)
{
id[x]=low[x]=++cnt;
int j,s=;
siz[x]=;
for (R i=firs[x];i;i=g[i].nex)
{
j=g[i].too;
if(!id[j])
{
dfs(j,roo);
low[x]=min(low[x],low[j]);
siz[x]+=siz[j];
if(low[j]>=id[x])
{
ans[x]+=(long long)s*siz[j];
s+=siz[j];
}
}
else
low[x]=min(low[x],id[j]);
}
ans[x]+=(long long)s*(n-s-);
} int main()
{
n=read();
m=read();
for (R i=;i<=m;++i)
{
x=read();
y=read();
add(x,y);
add(y,x);
}
for (R i=;i<=n;++i)
if(!id[i]) dfs(i,i);
for (R i=;i<=n;++i)
printf("%lld\n",(ans[i]+n-)<<);
return ;
}
BLO-blockade
其实割点的题比较少见唉...
$Tarjan$求割边(桥)
什么是割边呢?如果删去一条边后整个图变得不连通了,那么这条边就叫做这个图的一个割边。显然割边是对于无向图的一种东西,有向图是无法定义图的连通性的。
割点和割边听起来总是有种神奇的联系,所以有两个猜想:
1.两个割点中间连一条边一定是桥;
2.桥的两个端点都是割点;
然而并不是...都是错的...
如果对图上的边对于在搜索树上出现的位置进行分类,可以分为:树枝边(搜索树上的树枝),返祖边(指向搜索树上祖先的边),正向边(指向后代,但不是搜索树上的边),横叉边(指向搜索树与它不在同一子树上的边).然而无向图不存在横叉边.考虑反证法:如果$X$有指向其他子树的边,那必然也有从那边指过来的边,所以之前搜索时应该已经搜到过$X$了,这是不成立的.
那么一条边成为桥需要什么条件呢?首先对于搜索树上的一个节点$x$和它的子节点$y$,如果$low[y]>id[x]$,也就是说如果不走$(x,y)$这条边,$y$就无法与搜索树的其他部分相连通,那么$(x,y)$这条边就是一条割边.但是可以发现$low[y]<=id[y]$且$low[y]>id[x]$,而且$x$是$y$的直接祖先,所以可以认为是$low[y]=id[y]$,这就和缩点有一些相似之处了.这里有一些细节问题需要注意:怎样防止走反向边回到父亲去?一种最简单的方法是记录每个点在搜索书上的父亲.很可惜,这样做是错误的.如果一个点和它的父节点间有重边,那么这几条边肯定都不是割边,但是这样的做法却可能误判成割边.正确的做法是记录上一条走的边的编号且利用网络流反向边的标号技巧,注意不要走它即可。
来一道例题吧:
旅游航道:https://loj.ac/problem/10102
题意概述:求割边的数量。
# include <cstdio>
# include <iostream>
# include <cstring>
# define R register int using namespace std; const int maxn=;
int n,m,h,firs[maxn],low[maxn],id[maxn],cnt,x,y,ed;
struct edge
{
int too,nex;
}g[maxn<<]; void dfs (int x,int las)
{
int j;
low[x]=id[x]=++cnt;
for (R i=firs[x];i;i=g[i].nex)
{
j=g[i].too;
if(i==(las^)) continue;
if(!id[j]) dfs(j,i);
low[x]=min(low[x],low[j]);
if(low[j]>id[x]) ed++;
}
} void add (int x,int y)
{
g[++h].nex=firs[x];
firs[x]=h;
g[h].too=y;
} int main()
{
scanf("%d%d",&n,&m);
while(n||m)
{
h=;
cnt=ed=;
memset(firs,,sizeof(firs));
memset(id,,sizeof(id));
memset(low,,sizeof(low));
for (R i=;i<=m;++i)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
for (R i=;i<=n;++i)
if(!id[i]) dfs(i,-);
printf("%d\n",ed);
scanf("%d%d",&n,&m);
}
return ;
}
旅游航道
割边好像不是很难。但是,难的还在后面。
边双连通分量
边双连通分量是什么?
---shzr
Tarjan-割点&桥&双连通的更多相关文章
- 图的割点 桥 双连通(byvoid)
[点连通度与边连通度] 在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合.一个图的点连通度的定义为,最小割点集 ...
- tarjan算法应用 割点 桥 双连通分量
tarjan算法的应用. 还需多练习--.遇上题目还是容易傻住 对于tarjan算法中使用到的Dfn和Low数组. low[u]:=min(low[u],dfn[v])--(u,v)为后向边,v不是u ...
- BZOJ BLO 1123 (割点)【双连通】
<题目链接> 以下内容转自李煜东的<算法竞赛进阶指南> 题目大意:现在给定一张连通的无向图,不包含重边.现在输出$n$个整数,表示将第$i$个节点的所有与其它节点相关联的边去掉 ...
- [题解](tarjan割点/点双)luogu_P3225_矿场搭建
首先和割点有关,求割点,然后这些割点应该把这个图分成了多个点双,可以考虑点双的缩点,假如缩点做的话我们要分析每个点双的性质和贡献 先拿出一个点双来,如果它没有连接着割点,那么至少要建两个,以防止其中一 ...
- 图论之tarjan真乃神人也,强连通分量,割点,桥,双连通他都会
先来%一下Robert Tarjan前辈 %%%%%%%%%%%%%%%%%% 然后是热情感谢下列并不止这些大佬的博客: 图连通性(一):Tarjan算法求解有向图强连通分量 图连通性(二):Tarj ...
- HDU4612(Warm up)2013多校2-图的边双连通问题(Tarjan算法+树形DP)
/** 题目大意: 给你一个无向连通图,问加上一条边后得到的图的最少的割边数; 算法思想: 图的边双连通Tarjan算法+树形DP; 即通过Tarjan算法对边双连通缩图,构成一棵树,然后用树形DP求 ...
- Tarjan算法——强连通、双连通、割点、桥
Tarjan算法 概念区分 有向图 强连通:在有向图\(G\)中,如果两个顶点\(u, v\ (u \neq v)\)间有一条从\(u\)到\(v\)的有向路径,同时还有一条从\(v\)到\(u\)的 ...
- Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)【转】【修改】
一.基本概念: 1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成 ...
- (转)Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)
基本概念: 1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个 ...
随机推荐
- WebFrom与MVC异同
一.共同点 它们共用一套管道机制. 二.不同点: 1.开发方式: webform开发方式 第一步:前台页面(*.aspx)+后置代码类(*.cs) 第二步:前台页面(*.aspx)+一般处理程序(*h ...
- PCA算法学习(Matlab实现)
PCA(主成分分析)算法,主要用于数据降维,保留了数据集中对方差贡献最大的若干个特征来达到简化数据集的目的. 实现数据降维的步骤: 1.将原始数据中的每一个样本用向量表示,把所有样本组合起来构成一个矩 ...
- 使用cglib实现数据库框架的级联查询
写在前面的 这一章是之前写的<手把手教你写一个Java的orm框架> 的追加内容.因为之前写的数据库框架不支持级联查询这个操作,对于有关联关系的表用起来还是比较麻烦,于是就准备把这个功能给 ...
- Java基础——关于接口和抽象类的几道练习题
呃,一定要理解之后自己敲!!!这几道题,使我进一步了解了接口和抽象类. 1.设计一个商品类 字段: 商品名称,重量,价格,配件数量,配件制造厂商(是数组,因为可能有多个制造厂商) 要求: 有构造函数 ...
- 常见对象(int和String类型的相互转换)
public class Test03 { //基本数据类型包装类有八种,其中其中都有parsexxx的方法 //可以加将这七种字符串表现形式转换成基本数据类型 //char的包装类Character ...
- Saving HDU(hdu2111,贪心)
Saving HDU Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- 1-初识java
目录 java 历史 Java 平台 Java 开发环境 Java 运行原理[简] Java 历史 这里不详细记录java的历史,只是标记出时间点和事件. 时间点 事件 1991 Sun公司成立Gre ...
- redis主从|哨兵|集群模式
关于redis主从.哨兵.集群的介绍网上很多,这里就不赘述了. 一.主从 通过持久化功能,Redis保证了即使在服务器重启的情况下也不会损失(或少量损失)数据,因为持久化会把内存中数据保存到硬盘上,重 ...
- PDO中的预处理
PDO中的基本的原理和步骤和MySQL中的预处理都是一样的,只不过就是把MySQL中的预处理所有命令行的语法封装成了PDO对象的几个公开的方法而已! 1.发送预处理语句 此时,我们需要调用pdo对象的 ...
- Intellij Idea出现 unable to establish loopback connection
项目一运行就出现这个情况,好几次了,最后发现只要防火墙关闭,项目就可以运行成功.错误提示:“C:\Program Files\Java\jdk1.8.020\bin\java” -Xmx700m -D ...