培训补坑(day2:割点与桥+强联通分量)
补坑ing...
好吧,这是第二天。
这一天我们主要围绕的就是一个人:tarjan。。。。。。创造的强联通分量算法
对于这一天的内容我不按照顺序来讲,我们先讲一讲强联通分量,然后再讲割点与桥会便于理解
首先是强联通分量。。
所谓强联通分量即在一个集合中,所有的点都能互通,那么我们就称这一整个集合是一个强联通分量
那么我们怎么求一张图中有几个强联通分量呢?
首先我们要了解tarjan算法中最重要的2个数组(dfn数组:表示该点第一次出现在DFS序列中的时刻;low数组:表示该点所能追溯到的编号最小的节点(或者称为一个点能够到达的编号最小的节点,并且这2个节点互通(在有向图中)))
不废话,上图:
首先我们从任意一点开始dfs,直到走到底(出度为0)

如图我们发现6的出度为0,此时它的low数组与dfn数组相同,我们将他出队,并把它本身标记为一个强联通分量。

我们回到5,发现5和6的情况一样,自己就是一个强联通分量,然后5出队

然后我们继续从3号节点往下搜,发现搜到4号节点,4号节点又追溯到1号节点,发现一号节点已经访问过了,我们更新4的low数组,并将low数组回传。

然后我们从1号节点接着搜,搜到2号节点,2号节点又搜到了4号节点,而且4号节点又访问过了,所以我们认为1 2 3 4这是一个强联通分量,我们把所有low值为1的点都出队,发现队伍都空了,tarjan算法结束。
下面附上tarjan求强联通分量的代码
#include<cstdio>
inline int read()
{
int x=;char c;
while((c=getchar())<''||c>'');
for(;c>=''&&c<='';c=getchar())x=x*+c-'';
return x;
}
#define MN 10000
#define MM 50000
struct edge{int nx,t;}e[MM+];
int h[MN+],en,d[MN+],l[MN+],cnt,z[MN+],zn,inz[MN+],K;
inline void ins(int x,int y){e[++en]=(edge){h[x],y};h[x]=en;}
void tj(int x)
{
d[x]=l[x]=++cnt;inz[z[zn++]=x]=;
for(int i=h[x];i;i=e[i].nx)
{
if(!d[e[i].t])tj(e[i].t);
if(inz[e[i].t]&&l[e[i].t]<l[x])l[x]=l[e[i].t];
}
if(d[x]==l[x])for(++K;z[zn]!=x;)inz[z[--zn]]=;
}
int main()
{
int n,m,i;
n=read();m=read();
while(m--)i=read(),ins(i,read());
for(i=;i<=n;++i)if(!d[i])tj(i);
printf("%d",K);
}
不过提醒一下:本算法的退队是有问题的,如果出现多组数据需要将stack数组清0,或者在退队过程中把stack清0,具体原因如下:
假如我们上一次昨晚后的stack数组是这样的:

然后我们下一次继续做的时候,假如我们找到一个强联通分量,为1 2 3 4,进行退队操作:
(画图丑,不要介意)
那么我们会发现根本就不能退队,因为本来我们认为是空的地方的low和第一个点的low数组是一样的!所以就会出错!
————————————————我是分割线————————————————
那么我们已经讲完了强联通分量,回头来看看割点与桥:
我们先简单了解一下割点与桥的定义:
割点:假如这个点不存在整个有向图会变成2半
桥:假如不存在这条边,整个有向图会变成2半。
我们再把上面那张图搬出来:

在这张图中,割点有这几个:5,3,但是没有桥(尴尬了)
我们先看看割点的性质,显然割点后面的点的low数组都比割点的low数组大!对!就是这个性质!但是是不是除此之外就没有割点了呢?不是!在下一张图中我们会发现有满足这个性质但同样是割点的点。
所以我们只需要在tarjan算法的同时,在dfs中添加判断即可,但是注意,不要在整个dfs结束之后再来判断,因为我们有可能回溯到low数组比当前点小的点,不过我们不用考虑这些点,只要考虑之后的点就好了。
然后我们来看看下面这张图

这张图中红色的边就是一条桥,那么我们是否又发现了什么性质呢?是的,桥的终点的dfn数组等于low数组。因为如果5能够回溯到4以前的节点那么它就不是一条桥了。
来补一下割点的坑,在下一张图中,此时我们会发现,根节点也是一个割点,但是它并不满足上述割点的性质,所以,割点还有一个判断条件就是它是dfs树的根节点而且它有两棵以上的子树。

下面附上割点与桥的代码QAQ
#include<cstdio>
#define MN 500005
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int x,y,n,m,num=,tot=,dfsn;
int head[MN],low[MN],dfn[MN];
bool gedian[MN];
bool qiao[MN];
struct edge{
int to,next;
}g[MN*];
void ins(int u,int v){g[++num].next=head[u];head[u]=num;g[num].to=v;}
void tarjan(int u,int fa){
low[u]=dfn[u]=++dfsn;
int tmp=;
for(int i=head[u];i;i=g[i].next)
if(g[i].to!=fa)
if(!dfn[g[i].to]){
tarjan(g[i].to,u);
low[u]=min(low[u],low[g[i].to]);
tmp++;
if (low[g[i].to]>=dfn[u]) gedian[u]=true;
if(low[g[i].to]==dfn[g[i].to])qiao[i>>]=true;
}
else low[u]=min(low[u],dfn[g[i].to]);
if(fa==-&&tmp<=)gedian[u]=false;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)scanf("%d%d",&x,&y),ins(x,y),ins(y,x);
for(int i=;i<=n;i++)
if(!dfn[i])tarjan(i,-);
for(int i=;i<=n;i++)if(gedian[i])printf("%d ",i);
printf("\n");
for(int i=;i<=m;i++)if(qiao[i])printf("%d ",i);
printf("\n");
}
培训补坑(day2:割点与桥+强联通分量)的更多相关文章
- Tarjan 算法求割点、 割边、 强联通分量
Tarjan算法是一个基于dfs的搜索算法, 可以在O(N+M)的复杂度内求出图的割点.割边和强联通分量等信息. https://www.cnblogs.com/shadowland/p/587225 ...
- tarjan模板 强联通分量+割点+割边
// https://www.cnblogs.com/stxy-ferryman/p/7779347.html ; struct EDGE { int to, nt; }e[N*N]; int hea ...
- HDU 1269 迷宫城堡 【强联通分量(模版题)】
知识讲解: 在代码里我们是围绕 low 和 dfn 来进行DFS,所以我们务必明白 low 和 dfn 是干什么的? 有什么用,这样才能掌握他. 1. dfn[] 遍历到这个点的时间 2. ...
- HDU 4685 Prince and Princess(二分匹配+强联通分量)
题意:婚配问题,但是题目并不要求输出最大匹配值,而是让我们输出,一个王子可以与哪些王妃婚配而不影响最大匹配值. 解决办法:先求一次最大匹配,如果有两个已经匹配的王妃,喜欢她们两个的有两个或者以上相同的 ...
- [vios1023]维多利亚的舞会3<强联通分量tarjan>
题目链接:https://vijos.org/p/1023 最近在练强联通分量,当然学的是tarjan算法 而这一道题虽然打着难度为3,且是tarjan算法的裸题出没在vijos里面 但其实并不是纯粹 ...
- Kosaraju算法---强联通分量
1.基础知识 所需结构:原图.反向图(若在原图中存在vi到vj有向边,在反向图中就变为vj到vi的有向边).标记数组(标记是否遍历过).一个栈(或记录顶点离开时间的数组). 算法描叙: :对 ...
- [CF #236 (Div. 2) E] Strictly Positive Matrix(强联通分量)
题目:http://codeforces.com/contest/402/problem/E 题意:给你一个矩阵a,判断是否存在k,使得a^k这个矩阵全部元素都大于0 分析:把矩阵当作01矩阵,超过1 ...
- UVa 11324 & 强联通分量+DP
题意: 一张无向图,求点集使其中任意两点可到达. SOL: 强联通分量中的点要么不选要么全都选,然后缩点DAG+DP 记录一下思路,不想写了...代码满天飞.
- BZOJ 1051 & 强联通分量
题意: 怎么说呢...这种题目有点概括不来....还是到原题面上看好了... SOL: 求出强联通分量然后根据分量重构图,如果只有一个点没有出边那么就输出这个点中点的数目. 对就是这样. 哦还有论边双 ...
随机推荐
- C++基础 C++对类的管理——封装
1.封装 两层含义: (1)把事物的属性和方法结合成个整体. (2)对类的属性和方法进行访问控制,对不信的进行信息屏蔽. 2.访问控制 控制分为 类的内部,类的外部. public 修饰的成员,可在内 ...
- E - Nature Reserve CodeForces - 1059D
传送门 There is a forest that we model as a plane and live nn rare animals. Animal number iihas its lai ...
- P2341 [HAOI2006]受欢迎的牛(tarjan+缩点)
P2341 [HAOI2006]受欢迎的牛 题目描述 每头奶牛都梦想成为牛棚里的明星.被所有奶牛喜欢的奶牛就是一头明星奶牛.所有奶 牛都是自恋狂,每头奶牛总是喜欢自己的.奶牛之间的“喜欢”是可以传递的 ...
- startActivityForResult 请求码不正确
今天遇到一个坑,就是 startActivityForResult 接收不到正确的请求码. 比如,我startActivityForResult的时候,设置的请求码是4,但是接收到的时候是100032 ...
- qq登录面板
- 剑指Offer - 九度1507 - 不用加减乘除做加法
剑指Offer - 九度1507 - 不用加减乘除做加法2013-11-29 20:00 题目描述: 写一个函数,求两个整数之和,要求在函数体内不得使用+.-.*./四则运算符号. 输入: 输入可能包 ...
- mac安装虚拟机VirtualBox,并在虚拟机上安装centos
1. 首先从网页上https://www.virtualbox.org/wiki/Downloads下载VirtualBox-6.0.0-127566-OSXdmg文件.我一般把下载的文件放到/opt ...
- isinstance()判断数据类型
判断数据类型isinstance()l=[1,2,3]print(isinstance(l,list))#括号里面第一个填需要判断的数据,第二个是判断条件
- ASP.NET Core 认证与授权[1]:初识认证 (笔记)
原文链接: https://www.cnblogs.com/RainingNight/p/introduce-basic-authentication-in-asp-net-core.html 在A ...
- python /usr/bin/python^M: bad interpreter: No such file
今天在WingIDE下写了个脚本,传到服务器执行后提示: -bash: /usr/bin/autocrorder: /usr/bin/python^M: bad interpreter: No suc ...