1、基础知识

在有向图G,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components)。  下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达。{5},{6}也分别是两个强连通分量。

Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。栈中节点只有在其所属的强连通分量已经全部求出时,才会出栈。如果发现某节点u有边连到搜索树中栈里的节点v,则更新u的low
值为dfn[v](更新为low[v]也可以)。如果一个节点u已经DFS访问结束,而且此时其low值等于dfn值,则说明u可达的所有节点,都不能到达任何在u之前被DFS访问的节点 那么该节点u就是一个强连通分量在DFS搜索树中的根。此时将栈中所有节点弹出,包括u,就找到了一个强连通分量。

定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号。

  Low(u)=MIN{ DFN(u),  Low(v),(u,v)为树枝边,u为v的父节点,DFN(v),(u,v)为指向栈中节点的后向边(非横叉边)
}

  当DFN(u)=Low(u)时,以u为根的搜索子树上所有节点是一个强连通分量。

2、参考代码

 /* Tarjan算法:求一个有向图G=(V,E)里极大强连通分量。
强连通分量是指有向图G里顶点间能互相到达的子图。
如果一个强连通分量已经没有被其它强通分量完全包含,那这个强连通分量就是极大强连通分量*/
/*low[v]=dfn[v]时,栈里v以及v以上的顶点全部出栈,一个极大强连通分量*/
#include<stdio.h>
#include<stdlib.h>
#define MAXL 50
#define MIN(x,y) ((x) < (y) ? (x) : (y)) //结点定义
typedef struct edge_node{
int key;
struct edge_node *next;
}ENode;
typedef struct{
char vertex;
ENode *firstedge;
}VNode;
typedef VNode VList[MAXL];
typedef struct{
VList vlist;
int n,e;
}ALGraph;
int instack[MAXL]; //用于标记是否在栈中
int vis[MAXL];
int dfn[MAXL],low[MAXL];
int depth; int ind[MAXL]={}; int top;
int stack[MAXL]; //【【【要用到】】】
int num_scc; int count_SCCele;
int scc[MAXL];
ALGraph *ALG=(ALGraph *)malloc(sizeof(ALGraph)); //邻接表生成[有向图]
void creat_ALGraph(ALGraph *ALG)
{
int i,j,k;
char ch1,ch2;
ENode *ep; scanf("%d,%d",&ALG->n,&ALG->e);
for(i=;i<ALG->n;i++) //顶点表
{
getchar();
scanf("%c",&ALG->vlist[i].vertex);
ALG->vlist[i].firstedge=NULL;
}
for(k=;k<ALG->e;k++) //边表
{
getchar();
scanf("%c,%c",&ch1,&ch2);
for(i=;ALG->vlist[i].vertex!=ch1;i++);
for(j=;ALG->vlist[j].vertex!=ch2;j++); ep=(ENode*)malloc(sizeof(ENode));
ep->key=j;
ep->next=ALG->vlist[i].firstedge;
ALG->vlist[i].firstedge=ep;
}
} //邻接表输出
void print_ALGraph(ALGraph *ALG)
{
int i;
ENode *ptr=(ENode*)malloc(sizeof(ENode));
for(i=;i<ALG->n;i++)
{
printf("%c",ALG->vlist[i].vertex);
ptr=ALG->vlist[i].firstedge;
while(ptr!=NULL) //不能用!ptr
{
printf("->%c",ALG->vlist[ptr->key].vertex);
ptr=ptr->next;
}
printf("\n");
}
} //计算初始化用于dfnlow()和bicon()
void init_Tarjan(void)
{
depth=;
for(int i=;i<ALG->n;i++)
{
instack[i]=;
dfn[i]=low[i]=-;
vis[i]=;
} top=; //栈初始化
for(int j=;j<ALG->n;j++)
stack[j]=-;
num_scc=;
} void init_scc(void) //scc块初始化
{
count_SCCele=;
for(int i=;i<ALG->n;i++)
scc[i]=-;
} void SCC_Tarjan(int u)
{
int son;
ENode *ptr=(ENode *)malloc(sizeof(ENode)); dfn[u]=low[u]=depth++; //访问+访问标记+入栈+入栈标记+遍历
instack[u]=;
vis[u]=;
stack[top++]=u;
ptr=ALG->vlist[u].firstedge;
while(ptr!=NULL)
{
son=ptr->key;
if(!vis[son])
{
SCC_Tarjan(son);
low[u]=MIN(low[u],low[son]);
}
else if(instack[son]) //在栈中
{
low[u]=MIN(low[u],dfn[son]);
}
ptr=ptr->next;
}
if(dfn[u] == low[u]) //若此,以u为根的强连通分量
{
num_scc++;
init_scc();
do{
top--;
scc[count_SCCele++]=stack[top];
instack[stack[top]]=;
}while(stack[top] != u); for(int cn=;cn<count_SCCele;cn++)
printf("%c ",ALG->vlist[scc[cn]].vertex);
printf("\n");
}
} int main(void)
{
creat_ALGraph(ALG);
print_ALGraph(ALG); init_Tarjan();
for(int i=;i<ALG->n;i++) //***可以处理不连通的图,如果连通只需要一次即可,即给定一个root,直接bridge_Tarjan(root,-1)***
if(!vis[i])
SCC_Tarjan(i);
// SCC_Tarjan(2); //root可以自定义 printf("%d\n",num_scc); printf("%s %s %s\n","ver","dfn","low");
for(int l=;l<ALG->n;l++)
printf("%c: %3d %3d\n",ALG->vlist[l].vertex,dfn[l],low[l]); return ;
}

Tarjan算法---强联通分量的更多相关文章

  1. tarjan求强联通分量

    tarjan求强联通分量 变量含义说明: pre[i]:i点的被访问的时钟编号,被分配后保持不变 low[i]:i点能访问的最先的点的时钟编号,随子节点改变 scc_no[i]:i点所在的强联通分量的 ...

  2. Kosaraju算法---强联通分量

    1.基础知识 所需结构:原图.反向图(若在原图中存在vi到vj有向边,在反向图中就变为vj到vi的有向边).标记数组(标记是否遍历过).一个栈(或记录顶点离开时间的数组).      算法描叙: :对 ...

  3. Tarjan的强联通分量

    求强联通分量有很多种. <C++信息学奥赛一本通>  中讲过一个dfs求强联通分量的算法Kosdaraju,为了骗字数我就待会简单的说说.然而我们这篇文章的主体是Tarjan,所以我肯定说 ...

  4. Tarjan求强联通分量+缩点

    提到Tarjan算法就不得不提一提Tarjan这位老人家 Robert Tarjan,计算机科学家,以LCA.强连通分量等算法闻名.他拥有丰富的商业工作经验,1985年开始任教于普林斯顿大学.Tarj ...

  5. tarjan模板 强联通分量+割点+割边

    // https://www.cnblogs.com/stxy-ferryman/p/7779347.html ; struct EDGE { int to, nt; }e[N*N]; int hea ...

  6. USACO06JAN The Cow Prom /// tarjan求强联通分量 oj24219

    题目大意: n个点 m条边的图 求大小大于1的强联通分量的个数 https://www.cnblogs.com/stxy-ferryman/p/7779347.html tarjan求完强联通分量并染 ...

  7. tarjan求强联通分量 模板

    void tarjan(int u) { dfn[u]=low[u]=++dfs_clock; stack_push(u); for (int c=head[u];c;c=nxt[c]) { int ...

  8. 培训补坑(day2:割点与桥+强联通分量)

    补坑ing... 好吧,这是第二天. 这一天我们主要围绕的就是一个人:tarjan......创造的强联通分量算法 对于这一天的内容我不按照顺序来讲,我们先讲一讲强联通分量,然后再讲割点与桥会便于理解 ...

  9. 强联通分量-tarjan算法

    定义:在一张有向图中,两个点可以相互到达,则称这两个点强连通:一张有向图上任意两个点可以相互到达,则称这张图为强连通图:非强连通图有极大的强连通子图,成为强联通分量. 如图,{1},{6}分别是一个强 ...

随机推荐

  1. 【译】用jQuery 处理XML--写在前面的话

    用jQuery 处理XML--写在前面的话 用jQuery 处理XML-- DOM(文本对象模型)简介 用jQuery 处理XML--浏览器中的XML与JavaScript 用jQuery 处理XML ...

  2. 一句话解释c#中的特性,你了解多少

    自己闲着无聊写的,当然有些描述不是十分准确,毕竟一句话不能表达太多意思. 委托:把方法当做参数进行传递. 泛型:在类.方法中对使用的类型参数化. 匿名方法:委托及调用委托的简化版. Lambda表达式 ...

  3. MVVM架构~knockoutjs系列之级联select

    返回目录 对于下拉列表框的绑定在之前的knockoutjs文章中已经介绍过,今天主要说一下级联的select,事实上,在knockoutjs里,是以数据绑定为中心的,而数据是以面向对象为前提的,而对于 ...

  4. EF架构~EF6配置需要注意的几个地方

    回到目录 从EF5升级到EF6之后,可能会出现一些问题,这是正常的,任何系统的升级都没有一帆风顺的,当然这些不是我要说的重点,我真正要说的是,当出现这些问题时,我们应该如何去应对它,下面我总结了几个方 ...

  5. iOS开发——网络使用技术OC篇&网络爬虫-使用正则表达式抓取网络数据

    网络爬虫-使用正则表达式抓取网络数据 关于网络数据抓取不仅仅在iOS开发中有,其他开发中也有,也叫网络爬虫,大致分为两种方式实现 1:正则表达 2:利用其他语言的工具包:java/Python 先来看 ...

  6. hadoop本地库与系统版本不一致引起的错误解决方法

    hadoop本地库与系统版本不一致引起的错误解决方法 部署hadoop的集群环境为 操作系统 centos 5.8 hadoop版本为cloudera   hadoop-0.20.2-cdh3u3 集 ...

  7. 每天一个linux命令(9):touch 命令

    linux的touch命令不常用,一般在使用make的时候可能会用到,用来修改文件时间戳,或者新建一个不存在的文件. 1.命令格式: touch [选项]... 文件... 2.命令参数: -a    ...

  8. css图片叠加和底部定位

    css图片叠加和底部定位 css图片叠加 两张图片需要叠在一起显示,如何定位 容器先对定位 第一张图片正常摆放 第二张图片绝对定位,top:0px 这样便实现了两张图片叠加在一起了,设置z-index ...

  9. Pycharm远程调试

    1.在pycharm的安装目录中找到pycharm-debug.egg,将其拷贝到目标主机的/usr/lib/python2.7/dist-packages目录下: 执行: sudo easy_ins ...

  10. Java连接MongoDB进行增删改查

    1.导入必须的包: 详情看项目:http://pan.baidu.com/s/1cvDAOY 2.通过Myeclipse创建WEB项目 3. 3.bean:创建实体类 package com.bean ...