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. linux MySQL5.7 rpm安装(转)

    删除旧包: # rpm -qa | grep -i mysql # rpm -ev mysql-libs-* --nodeps 安装rpm包: # rpm -ivh mysql-community-c ...

  2. Dice Similarity Coefficent vs. IoU Dice系数和IoU

    Dice Similarity Coefficent vs. IoU Several readers emailed regarding the segmentation performance of ...

  3. (ACP)敏捷项目管理

    第1章 为什么需要敏捷 第2章 敏捷和敏捷项目管理定义 第3章 敏捷项目管理价值和原则 1.我们的最高目标是,通过尽早持续交付有价值的软件来满足客户的需求 2.欢迎对需求提出变更,即使在项目开发后期也 ...

  4. Gamma阶段第二次scrum meeting

    每日任务内容 队员 昨日完成任务 明日要完成的任务 张圆宁 #91 用户体验与优化https://github.com/rRetr0Git/rateMyCourse/issues/91(持续完成) # ...

  5. WINDOWS 命令行调用SAS代码 并指定输出路径 示例

    ECHO "设置SAS.EXE 路径" SET PATH=D:\Program Files\SASHome\SASFoundation\9.4\SAS.EXE echo " ...

  6. 主题模型TopicModel:主题模型LDA的应用

    http://blog.csdn.net/pipisorry/article/details/45665779 主题模型LDA的应用 拿到这些topic后继续后面的这些应用怎么做呢:除了推断出这些主题 ...

  7. 【maven】maven下载依赖jar的源码

    mvn dependency:sourcesmvn dependency:resolve -Dclassifier=javadoc 命令使用方法:首先进入到相应的pom.xml目录中,然后执行以上命令 ...

  8. java 把 PEM 格式的公钥证书转换为 X.509 格式的证书

    代码: @UtilityClass public final class X509Certs { private static final CertificateFactory CERTIFICATE ...

  9. GEOS/GDAL 交叉编译ARM64-linux版本

    目录 安装编译环境 编译PROJ.4 编译GEOS 编译GDAL 编译后程序运行注意事项 因为试用华为云ARM64服务器(CentOS 7 操作系统)的时候,在云服务器上编译GDAL很长时间也没有编译 ...

  10. windows7平台android studio新建Android项目,报错

    Failed to install the following Android SDK packages as some licences have not been accepted. platfo ...