[算法]tarjan
Posted hdsmwww
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[算法]tarjan相关的知识,希望对你有一定的参考价值。
!!!血泪史!!!
tmp不能设全局变量!!!
以下摘自SHHHS
Tarjan 算法
一.算法简介
Tarjan 算法一种由Robert Tarjan提出的求解有向图强连通分量的算法,它能做到线性时间的复杂度。
我们定义:
如果两个顶点可以相互通达,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量(strongly connected components)。
例如:在上图中,{1 , 2 , 3 , 4 } , { 5 } , { 6 } 三个区域可以相互连通,称为这个图的强连通分量。
Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。
再Tarjan算法中,有如下定义。
DFN[ i ] : 在DFS中该节点被搜索的次序(时间戳)
LOW[ i ] : 为i或i的子树能够追溯到的最早的栈中节点的次序号
当DFN[ i ]==LOW[ i ]时,为i或i的子树可以构成一个强连通分量。
二.算法图示
以1为Tarjan 算法的起始点,如图
顺次DFS搜到节点6
回溯时发现LOW[ 5 ]==DFN[ 5 ] , LOW[ 6 ]==DFN[ 6 ] ,则{ 5 } , { 6 } 为两个强连通分量。回溯至3节点,拓展节点4.
拓展节点1 , 发现1再栈中更新LOW[ 4 ],LOW[ 3 ] 的值为1
回溯节点1,拓展节点2
自此,Tarjan Algorithm 结束,{1 , 2 , 3 , 4 } , { 5 } , { 6 } 为图中的三个强连通分量。
不难发现,Tarjan Algorithm 的时间复杂度为O(E+V).
1 #include<cstdio> 2 #include<cmath> 3 #define LL long long 4 #define M 20010 5 #define mod 6 using namespace std; 7 int read() 8 { 9 int x=0,f=1; 10 char ch=getchar(); 11 while(!isdigit(ch)){if(ch==\'-\')f=-1;ch=getchar();} 12 while(isdigit(ch)){x=x*10+ch-\'0\';ch=getchar();} 13 return x*f; 14 } 15 int n,m,T,top,ans,dfn_cnt; 16 int first[M],next[M<<5],dfn[M],low[M],u[M<<5],v[M<<5],stack[M]; 17 bool vis[M],book[M]; 18 void tarjan(int x) 19 { 20 vis[x]=book[x]=1; 21 dfn[x]=low[x]=++dfn_cnt; 22 stack[++top]=x; 23 for(int i=first[x];i!=-1;i=next[i]) 24 { 25 int tmp=v[i]; 26 if(!dfn[tmp]) tarjan(tmp); 27 if(vis[tmp]==1) low[x]=min(low[x],low[tmp]); 28 } 29 if(dfn[x]==low[x]) 30 { 31 ans++; 32 while(stack[top]!=x) vis[stack[top--]]=0; 33 vis[x]=0,top--; 34 } 35 } 36 int main() 37 { 38 T=read(); 39 while(T--) 40 { 41 ans=top=dfn_cnt=0,n=read(),m=read(); 42 memset(first,-1,sizeof(first)); 43 memset(next,0,sizeof(next)); 44 memset(dfn,0,sizeof(dfn)); 45 memset(book,false,sizeof(book)); 46 for(int i=1;i<=m;i++) 47 { 48 u[i]=read();v[i]=read(); 49 next[i]=first[u[i]]; 50 first[u[i]]=i; 51 } 52 for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); 53 printf("%d\\n",ans); 54 } 55 return 0; 56 }
以上是关于[算法]tarjan的主要内容,如果未能解决你的问题,请参考以下文章