强连通:在有向图G中,两个顶点间至少存在一条路径,则两个点强连通。

强连通图:在有向图中,每两个顶点都强连通,则有向图G就是一个强连通图。

强连通分量:在非强连通图中的极大强连通子图,就称为强连通分量。

直接根据定义,可以通过双向遍历取交集的方法求强连通分量,但是其复杂度为O(N^2+M)。更好的方法是用tarjan算法,其时间复杂度为O(N+M)。

tarjan:其实就是对图的深度优先遍历。

算法模拟:

定义 DFN [u]为节点u被搜索到时的次序编号(也就是所遍历的第几个);

定义LOW[U]为U或者U 的子数能够追溯到最早的栈中节点的次序号。

  (当DFN[U] ==  LOE[U] 时,以U为根的搜索子树上所有节点是一个强连通分量。实质上就是这个点的整个子树回溯完了,没有链接的路了)

此时的F点DNF[F]==LOW[F]=4,所以F为一个强连通分量,只有它自己本身。

然后返回节点E,此时发现 DFN[E] == LOW[E] =5,所以E也单独为一个强连通分量,只有他本身。

然后返回节点C:

从C节点继续搜其他的C的子树,搜到节点D,将D加入栈中。然后D有  D ->  F ,但是F 已经出栈,所以F节点直接跳过,

还有一个节点A , 但是呢,A节点已经在栈中,所以LOW[D] = DFN[A] = 1,然后是一个回溯的过程,所以呢,LOW[C] = LOW [D] =1;

所以说明这三个节点已经是一个强连通分量了。

继续回到节点A,最后访问B节点,,然后 B-> D ,然而 D点还在栈中,所以LOW[B] = DFN [ D ] = 5 ,DFN[B] = 6 ;

没有其他点了,算法结束,最后得到 {A,B,C,D} ,{E}, {F}为强连通分量。

在tarjan算法中,每个点只被访问了一次,而且只进行了一次的栈,每条边也只被访问了一次,。所以该算法的时间复杂度为O(N+M);

程序模板:

 #include <cstdio>
#include <cstring>
#include <iostream>
using namespace std; #define N 100
#define M 100 struct node
{
int v;
int next;
}; node edge[M];//边的集合 int a[N];//顶点的集合
int instack[N];//模拟栈,标记是否在栈中
int stack[N];
int belong[N];//各个顶点属于哪个强连通分量
int DFN[N];
int LOW[N];//栈中能够追溯到最早的节点序号
int n;//点的个数
int m;//边的个数
int count;//边的计数器
int index;//序号(时间戳)
int top;
int sun;//强连通分量的个数 //用邻接表存储
void add_edge(int u,int v)
{
edge[count].next=a[u];
edge[count].v=v;
a[u]=count++;
} void tarjan(int u)
{
int i,j;
int v;
DFN[u]=LOW[u]=++index;
instack[u]=true;
stack[++top]=u;//进栈
for(i=a[u];i!=-;i=edge[i].next)
{
v=edge[i].v;
if(!DFN[v])//如果DFN[v]为0,没被访问
{
tarjan(v);
//一个回溯的过程
if(LOW[v]<LOW[u])
LOW[u]=LOW[v];
}
else
{
if(instack[v]&&DFN[v]<LOW[u])
LOW[u]=DFN[v];
}
}
if(DFN[u]==LOW[u])
{
sun++;
//出栈
do
{
j=stack[top--];
instack[j]=false;
belong[j]=sun;
}while(j!=u); }
} void solve()
{
int i;
top=index=sun=;
memset(DFN,,sizeof(DFN));
memset(LOW,,sizeof(LOW));
for(i=;i<=n;i++)
{
if(!DFN[i])
tarjan(i);
}
} int main()
{
int i,j,k;
count=;
memset(a,-,sizeof(a));
scanf("%d %d",&n,&m);
for(i=;i<=m;i++)
{
scanf("%d %d",&j,&k);
add_edge(j,k);
}
solve();
for(i=;i<=n;i++)
printf("%d ",belong[i]);
}

tarjan有向图的强连通的更多相关文章

  1. HDU1269迷宫城堡(裸Tarjan有向图求强连通分量个数)

    迷宫城堡Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submiss ...

  2. 『Tarjan算法 有向图的强连通分量』

    有向图的强连通分量 定义:在有向图\(G\)中,如果两个顶点\(v_i,v_j\)间\((v_i>v_j)\)有一条从\(v_i\)到\(v_j\)的有向路径,同时还有一条从\(v_j\)到\( ...

  3. UVA247- Calling Circles(有向图的强连通分量)

    题目链接 题意: 给定一张有向图.找出全部强连通分量,并输出. 思路:有向图的强连通分量用Tarjan算法,然后用map映射,便于输出,注意输出格式. 代码: #include <iostrea ...

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

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

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

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

  6. 图->连通性->有向图的强连通分量

    文字描述 有向图强连通分量的定义:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly co ...

  7. DFS的运用(二分图判定、无向图的割顶和桥,双连通分量,有向图的强连通分量)

    一.dfs框架: vector<int>G[maxn]; //存图 int vis[maxn]; //节点访问标记 void dfs(int u) { vis[u] = ; PREVISI ...

  8. uva11324 有向图的强连通分量+记忆化dp

    给一张有向图G, 求一个结点数最大的结点集,使得该结点集中任意两个结点u和v满足,要么u可以到达v, 要么v可以到达u(u和v相互可达也可以). 因为整张图可能存在环路,所以不好使用dp直接做,先采用 ...

  9. 图论-求有向图的强连通分量(Kosaraju算法)

    求有向图的强连通分量     Kosaraju算法可以求出有向图中的强连通分量个数,并且对分属于不同强连通分量的点进行标记. (1) 第一次对图G进行DFS遍历,并在遍历过程中,记录每一个点的退出顺序 ...

随机推荐

  1. 加载和执行 --《高性能JavaScript》

    1.起因: 每次遇到<script> 标签时,页面必须停下来等待代码下载并执行完,然后再继续处理其他部分. 2.减少JavaScript对性能的影响 1.将所有的JavaScript文件放 ...

  2. Comparable 和 Comparator的理解

    对Comparable 的解释 Comparable是一个排序接口 此接口给实现类提供了一个排序的方法,此接口有且只有一个方法 public int compareTo(T o); compareTo ...

  3. python day - 17 面向对象的 类空间 和 组合

    1. 类命名空间 在类的代码中,当python 解释器在 运行的那一刻.就会在内存中开辟一个类空间,在类的空间中会加载静态变量,以及类方法的内存地址. 当类名+()(也就是实例化过程中),内存中会再次 ...

  4. Oracle数据库案例整理-Oracle系统执行时故障-断电导致数据文件状态变为RECOVER

    1.1      现象描写叙述异常断电.数据库数据文件的状态由ONLINE变为RECOVER. 系统显演示样例如以下信息:SQL>selectfile_name,tablespace_name, ...

  5. ie下文件上传无权访问的问题

    最近项目遇到个问题,ie下文件上传无权访问,在网上找了很久才找到答案,原来是因为ie下不能用js触发input=file的点击事件,必须手动点击才可以.

  6. iOS 开发用到的常用工具

    如果你去到一位熟练的木匠的工作室,你总是能发现他/她有一堆工具来完成不同的任务. 软件开发同样如此.你可以从软件开发者如何使用工具中看出他水准如何.有经验的开发者精于使用工具.对你目前所使用的工具不断 ...

  7. HDU 3714/UVA1476 Error Curves

    Error Curves Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tota ...

  8. js与原生的交互

    一.与安卓的交互 Android与js通过WebView互相调用方法,实际上是: Android去调用JS的代码 JS去调用Android的代码 二者沟通的桥梁是WebView 对于android调用 ...

  9. ES6 数组的解构赋值

    数组的解构赋值 ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring). 以前,为变量赋值,只能直接指定值. let a = 1; let b = ...

  10. 【转载】浅谈Excel开发:一 Excel 开发概述

    博客园就是好,想要什么都给总结了,多谢 原文转载:http://www.cnblogs.com/yangecnu/p/Excel-Develpment-Introduction.html 做Offic ...