Tarjan算法:一种由Robert Tarjan提出的求解有向图强连通分量的线性时间的算法。

定义给出之后,让我们进入算法的学习。。。

【情境引入】

【HAOI2006受欢迎的牛】

题目描述:

每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶

牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果A喜

欢B,B喜欢C,那么A也喜欢C。牛栏里共有N 头奶牛,给定一些奶牛之间的爱慕关系,请你

算出有多少头奶牛可以当明星。

可以看出,当将每一个强连通分量视为每一个点时,受欢迎的奶牛只有可能是图中唯一的出度为零的点中的所有奶牛

这个时候,强连通分量的求得就出现了问题,这个时候,Tarjan算法应运而生

概念引入:

在有向图G中,如果两个顶点可以相互到达,则称两个顶点强连通。
如果有向图G的任意两个顶点都强连通,称G是一个强连通图。
非强连通有向图的极大强连通子图,称为强连通分量。
下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达。{5},{6}也分别是两个强连通分量。

算法实现:

Tarjan算法是基于对图深度优先搜索的算法。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。

相比看完这个莫名其妙的东西很少有人能理解,那就让我们进入具体讲解:

算法准备:

dep[x]为节点x搜索的次序编号(时间戳,即搜索x的深度)。

low[x]为x或x的子树能够追溯到的最早的栈中节点的次序号。

当dep[x]=low[x]时,以x为根的搜索子树上所有节点是一个强连通分量。

4个细节

前提:搜索x->y这条边时。 初始状态deep[x]=low[x]=++tot;

如果y没有被搜过,那就入栈,深搜y,回溯时更新low[x]=min(low[x],low[y]);

如果y被搜过,并且在栈中,不再深搜y,而是直接更新low[x]=min(low[x],deep[y]);

当x所有的出边都处理完了,在这个过程中low[x]可能被多次修改

如果任然存在deep[x]==low[x],那么弹栈,直到弹出元素为x停止。那么这次弹出的所有元素就构成了一个强联通分量。

还有不太明白的同学可以手推一下这张网上疯传的tarjan讲解图(动画懒得做了)

那么废话少说,上受欢迎的牛代码,没推明白的同学还可以看代码

代码如下:

#include<bits/stdc++.h>
using namespace std;
struct SYM{
int to,next,fro;
}edge[];
int head[],n,m,tot,dep[],low[],belong[],sta[],vis[],top,num[];
void addedge(int x,int y){
edge[++tot].to=y;
edge[tot].fro=x;
edge[tot].next=head[x];
head[x]=tot;
}
int indx,cnt;
void tarjan(int x){
dep[x]=low[x]=++indx;
sta[++top]=x;
vis[x]=;
for(int i=head[x];i;i=edge[i].next){
int to=edge[i].to;
if(!dep[to]){
tarjan(to);
low[x]=min(low[x],low[to]); //如果y没有被搜过,那就入栈,深搜y,回溯时更新low[x]=min(low[x],low[y]);
}
else if(vis[to]){
low[x]=min(low[x],dep[to]); //如果y被搜过,并且在栈中,不再深搜y,而是直接更新low[x]=min(low[x],deep[y]);
}
}
if(dep[x]==low[x]){ //如果任然存在deep[x]==low[x],那么弹栈,直到弹出元素为x停止。那么这次弹出的所有元素就构成了一个强联通分量。
cnt++;
int hh=-;
while(x!=hh){
hh=sta[top--];
belong[hh]=cnt;
num[cnt]++;
vis[hh]=;
}
}
}
int od[];
int main(){
int x,y;
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++){
scanf("%d%d",&x,&y);
addedge(x,y);
}
for(int i=;i<=n;i++)
if(!dep[i]) tarjan(i); //跑tarjan(怕是废话)
for(int i=;i<=m;i++)
if(belong[edge[i].fro]!=belong[edge[i].to])
od[belong[edge[i].fro]]++; //对每一条边进行处理,如果两个端点不属于一个强连通分量则对缩出来的点之间连边
int hhh=,ans;
for(int i=;i<=cnt;i++){ //计算有几个出度为一的点
if(od[i]==){
hhh++;
ans=i;
}
}
if(hhh==) printf("%d",num[ans]);
else printf("");
return ;
}

其他例题:

消息扩散

【校园网Network of Schools】

【[USACO06JAN]牛的舞会The Cow Prom】

over~

Tarjan求有向图强连通分量 BY:优少的更多相关文章

  1. Tarjan算法求有向图强连通分量并缩点

    // Tarjan算法求有向图强连通分量并缩点 #include<iostream> #include<cstdio> #include<cstring> #inc ...

  2. Tarjan求有向图强连通详解

    Tarjan求有向图强连通详解 注*该文章为转发,原文出处已经不得而知 :first-child { margin-top: 0; } blockquote > :last-child { ma ...

  3. KS求有向图强连通分量模板

    #include<bits/stdc++.h> using namespace std; typedef long long ll; int n,m; ; *maxn; struct no ...

  4. 有向图强连通分量的Tarjan算法

    有向图强连通分量的Tarjan算法 [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G ...

  5. POJ3180(有向图强连通分量结点数>=2的个数)

    The Cow Prom Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 1451   Accepted: 922 Descr ...

  6. 有向图强连通分量 Tarjan算法

    [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极 ...

  7. 【转】有向图强连通分量的Tarjan算法

    原文地址:https://www.byvoid.com/blog/scc-tarjan/ [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly con ...

  8. 有向图强连通分量的Tarjan算法和Kosaraju算法

    [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极 ...

  9. Tarjan算法求出强连通分量(包含若干个节点)

    [功能] Tarjan算法的用途之一是,求一个有向图G=(V,E)里极大强连通分量.强连通分量是指有向图G里顶点间能互相到达的子图.而如果一个强连通分量已经没有被其它强通分量完全包含的话,那么这个强连 ...

随机推荐

  1. 文件搜索命令(命令搜索)which、whereis

    一.which命令: 搜索命令所在目录(绝对路径)或者别名信息. 用户可以使用的命令存放在: /bin /usr/bin 管理员使用的命令: /sbin /usr/sbin 1.带有别名的命令: 二. ...

  2. 用jdk1.6的pack200和unpack200,对jar文件进行压缩和解压 .pack.gz

    用jdk1.6的pack200和unpack200,对jar文件进行压缩和解压 解压xxx.jar.pack.gz为xxx.jar:unpack200 -r xxx.jar.pack.gz xxx.j ...

  3. SpringCloud:搭建基于Gateway的微服务网关(一)

    1.需求 最近在尝试着写一个开放平台,于是先搭建网关. 作用:统一的请求入口,完成对请求的跟踪,限流(未做),鉴权,分发,封装响应 2.工作原理 2.1.请求 在开放平台中申请对接口的使用,申请通过后 ...

  4. Debian 环境安装新版 nginx

    在 Debian 系统中,我们可以通过 apt-get 安装系统自带的 nginx,这样安装的 nginx 版本略旧.Nginx 官网提供了一些编辑绎好的 deb 安装包,我们只需更新安装源,就可以通 ...

  5. 【Gamma】Scrum Meeting 4 & 助教参会记录

    目录 前言 任务分配 燃尽图 会议照片 签入记录 上周助教交流总结 技术博客 一些说明 前言 第4次会议于5月29日22:00线上交流形式召开. 交流确认了各自的任务进度,并与助教进行了沟通.时长20 ...

  6. docker run 中的privileged参数

    docker 应用容器 获取宿主机root权限(特殊权限-) docker run -d --name="centos7" --privileged=true centos:7 / ...

  7. 源码方式安装 lrzsz 库

    我们都知道安装了lrzsz工具的linux系统环境: 在shell里可以非常方便的上传和下载linux里面的文件: 通常的安装方式: yum install lrzsz sudo apt-get in ...

  8. tensorflow 笔记 16:tf.pad

    函数: tf.compat.v1.pad tf.pad 函数表达式如下: tf.pad(    tensor,    paddings,    mode='CONSTANT',    name=Non ...

  9. java多线程(五)线程通讯

    1.1. 为什么要线程通信 多个线程并发执行时,在默认情况下CPU是随机切换线程的,有时我们希望CPU按我们的规律执行线程,此时就需要线程之间协调通信. 1.2. 线程通讯方式 线程间通信常用方式如下 ...

  10. IfcAxis2Placement3D

    The IfcAxis2Placement3D provides location and orientations to place items in a three-dimensional spa ...