【原创】tarjan算法初步(强连通子图缩点)

tarjan算法的思路不是一般的绕!!(不过既然是求强连通子图这样的回路也就可以稍微原谅了。。)

但是研究tarjan之前总得知道强连通分量是什么吧。。

上百度查查:

  有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量(strongly connected components)。

看不懂。。那么——

看这张图

其中从1可以到2,3,4,5,6;

从2可以到1,3,4,5,6;

从3可以到6;

从4可以到1,2,3,5,6;

从5可以到1,2,3,4,6;

从6哪儿都到不了。

我们发现,{1,2,4,5}两两可以互达,我们称其为原图的一个强连通子图,而{3},{6}各自单独为原图的另外两个强连通子图。

我们想要通过程序实现O(n)求所有强连通子图,就要用到tarjan算法。

程序代码如下(tarjan的主要思路写在程序注释里,若无法理解请参考另一篇【转载】全网最!详!细!tarjan算法讲解):

 // Tarjan有向图强连通缩点
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<string>
#define MAXV 10010
#define MAXE 100010
using namespace std;
struct tEdge{
int np;
tEdge *next;
}E[MAXE],*V[MAXV];
int tope=-;
int n,m;
int dfn[MAXV],dfstime=; // dfn[i]表示点i的dfs序
int low[MAXV]; // low[i]表示目前点i所能到达的最小dfs序点
int status[MAXV]; // status[i]表示点i的访问状态,0=未访问,1=访问中,2=访问完毕
int stack[MAXV],tops=-;
int color[MAXV],totc=; // color[]表示缩点后的块
void addedge(int u,int v){
E[++tope].np=v;
E[tope].next=V[u];
V[u]=&E[tope];
}
void tarjan(int now){
stack[++tops]=now; // 进栈
low[now]=dfn[now]=++dfstime; // 初始化dfs序
status[now]=; // 访问中(在栈中)
for(tEdge *ne=V[now];ne;ne=ne->next){
if(status[ne->np]==){ // 未访问(没有进过栈)
tarjan(ne->np); // dfs往下进行递归访问
low[now]=min(low[now],low[ne->np]);
// 由于now可达ne->np,故ne->np可达的最小dfs序点从now也可达
}
else if(status[ne->np]==){ // 回边,发现ne->np为栈中元素
low[now]=min(low[now],dfn[ne->np]);
// 若ne->np的dfs序比原来now可达的最小dfs序还小则更新
}
}
if(low[now]==dfn[now]){
// now到达的最小dfs序为自己dfs序
// 即now不包含在最小dfs序更小的缩点中
// 而栈中now以后的节点若不能到达now则早已出栈(FILO)
totc++; // 申请新颜色(一种颜色代表一个缩点)
while(stack[tops+]!=now){ // 栈中所有在now之后的节点都在该缩点内
status[stack[tops]]=; // 访问完毕(已出栈)
color[stack[tops--]]=totc; // 为节点染色
}
}
}
int main(){
memset(dfn,,sizeof(dfn));
memset(low,,sizeof(low));
memset(status,,sizeof(status));
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
}
for(int i=;i<=n;i++)
if(status[i]==)
tarjan(i); // 图不连通时必须保证每个点都处理到
for(int i=;i<=n;i++)
printf("Point %d colored %d\n",i,color[i]); // 输出所属强连通块编号
return ;
}

测试数据:


运行结果:

Point  colored
Point colored
Point colored
Point colored
Point colored
Point colored

即color[1]={6},color[2]={3},color[3]={1,2,4,5}为原图的3个强连通子图的缩点。

【原创】tarjan算法初步(强连通子图缩点)的更多相关文章

  1. Tarjan算法分解强连通分量(附详细参考文章)

    Tarjan算法分解强连通分量 算法思路: 算法通过dfs遍历整个连通分量,并在遍历过程中给每个点打上两个记号:一个是时间戳,即首次访问到节点i的时刻,另一个是节点u的某一个祖先被访问的最早时刻. 时 ...

  2. tarjan算法(强连通分量 + 强连通分量缩点 + 桥(割边) + 割点 + LCA)

    这篇文章是从网络上总结各方经验 以及 自己找的一些例题的算法模板,主要是用于自己的日后的模板总结以后防失忆常看看的, 写的也是自己能看懂即可. tarjan算法的功能很强大, 可以用来求解强连通分量, ...

  3. Tarjan算法初步

    一.前置知识: 强连通分量:有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(stron ...

  4. Tarjan在图论中的应用(一)——用Tarjan来实现强连通分量缩点

    前言 \(Tarjan\)是一个著名的将强连通分量缩点的算法. 大致思路 它的大致思路就是在图上每个联通块中任意选一个点开始进行\(Tarjan\)操作(依据:强连通分量中的点可以两两到达,因此从任意 ...

  5. [学习笔记] Tarjan算法求强连通分量

    今天,我们要探讨的就是--Tarjan算法. Tarjan算法的主要作用便是求一张无向图中的强连通分量,并且用它缩点,把原本一个杂乱无章的有向图转化为一张DAG(有向无环图),以便解决之后的问题. 首 ...

  6. HDU 1269 迷宫城堡 tarjan算法求强连通分量

    基础模板题,应用tarjan算法求有向图的强连通分量,tarjan在此处的实现方法为:使用栈储存已经访问过的点,当访问的点离开dfs的时候,判断这个点的low值是否等于它的出生日期dfn值,如果相等, ...

  7. Tarjan算法【强连通分量】

    转自:byvoid:有向图强连通分量的Tarjan算法 Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树.搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断 ...

  8. Tarjan 算法求 LCA / Tarjan 算法求强连通分量

    [时光蒸汽喵带你做专题]最近公共祖先 LCA (Lowest Common Ancestors)_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili tarjan LCA - YouTube Tarj ...

  9. 【算法】Tarjan算法求强连通分量

    概念: 在有向图G中,如果两个定点u可以到达v,并且v也可以到达u,那么我们称这两个定点强连通. 如果有向图G的任意两个顶点都是强连通的,那么我们称G是一个强连通图. 一个有向图中的最大强连通子图,称 ...

随机推荐

  1. 监控 Kubernetes 集群应用

    Prometheus的数据指标是通过一个公开的 HTTP(S) 数据接口获取到的,我们不需要单独安装监控的 agent,只需要暴露一个 metrics 接口,Prometheus 就会定期去拉取数据: ...

  2. 10-MySQlL DBA笔记-基础知识

    第四部分 运维篇 首先来了解一下数据库的定义,数据库是高效的.可靠的.易用的.安全的多用户存储引擎,我们可以通过它访问大量的持久化数据.我们管理和维护数据库,本质上也是要确保如上的特性,尽可能地保证数 ...

  3. MangoDB CSharp Driver

    1.引用MongoDB for C# Driver 从网上下载C#访问MongoDB的驱动,得到两个DLL: MongoDB.Driver.dll MongoDB.Bson.dll 将它们引用到项目中 ...

  4. ASP.NET 中的 Session 怎么正确使用

    Session对象用于存储从一个用户开始访问某个特定的aspx的页面起,到用户离开为止,特定的用户会话所需要的信息.用户在应用程序的页面切换时,Session对象的变量不会被清除. 对于一个Web应用 ...

  5. 守护服务Supervisor的安装和使用

    Supervisor(http://supervisord.org/)是用Python开发的一个client/server服务,是Linux/Unix系统下的一个进程管理工具,不支持Windows系统 ...

  6. Spark RDD学习笔记

    一.学习Spark RDD RDD是Spark中的核心数据模型,一个RDD代表着一个被分区(partition)的只读数据集. RDD的生成只有两种途径: 一种是来自于内存集合或外部存储系统: 另一种 ...

  7. docker 无法使用vi

    更新来源 apt-get update   安装vim apt-get install -y vim

  8. netstat用法详解

    netstat用法详解 知识,netstat用法详解 图片 netstat用法详解 内容,netstat用法详介绍,netstat用法详正文 netstat命令是一个监控TCP/IP网络的非常有用的工 ...

  9. LLVM的RTTI特性

    本文思路来源于http://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html,叙述有不同,望谅解,希望能从其他方面帮助大家了解C++语言的底层实现. 背景 在LLV ...

  10. 支持向量机通俗导论 ——理解SVM的三层境界 总结

    1.什么是支持向量机(SVM) 所谓支持向量机,顾名思义,分为两部分了解:一,什么是支持向量(简单来说,就是支持或支撑平面上把两类类别划分开来的超平面的向量点):二,这里的“机(machine,机器) ...