tarjan算法求强连通分量

第一篇博客,尽管园龄已经一年了。。

 

tarjan算法求强连通分量

有种tarjan算法是求强连通分量的。

那强连通分量是啥呢?

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

(如还不懂就点

such as:

 

该图中共有三个强连通分量,分别为【1,2,3,4】、【5】、【6】。

1,2,3,4之间可以相互到达,而5和6只能到达自己,所以分成了以上三个分量。

要找强连通分量,使用链表与深搜结合的办法:

建好表后,以每一个点为起点都深搜一次,这里需要维护两个数组,一个是dfn[N],一个是low[N]。

dfn[v]表示顶点v被访问的时间,low[v]表示与顶点v邻接的未删除的顶点u的low[v]与low[u]的最小值。

在深搜的回溯过程中,如果dfn[v]==low[v],那么当前顶点就是一个强连通分量的根(由于不断维护low数组,所以该强连通分量中所有节点的low都为第一遍深搜时时间。如果不是强连通分量的根,那么一定属于另一个强连通分量,而且它的根是当前顶点的祖宗,那么存在包含当前顶点的到其祖宗的回路,可知low[v]一定会被更改为一个比dfn[v]更小的值

下附代码

 

 1 #include<cstdio>
 2 #include<stack>
 3 #define N 420000
 4 using namespace std;
 5 stack<int>p; 
 6 struct hehe{ 
 7     int next;
 8     int to;
 9 }edge[N];
10 int head[N],num_edge;
11 int time;
12 int dfn[N]; 
13 int low[N]; 
14 int ans1,ans2;
15 int x,y,n,m;
16 int place[N];
17 bool f[N]; 
18 bool k;
19 void add_edge(int from,int to){ 
20     edge[++num_edge].next=head[from];
21     edge[num_edge].to=to;
22     head[from]=num_edge;
23 }
24 void dfs(int x){
25     k=0;
26     p.push(x);
27     dfn[x]=low[x]=++time; 
28     for(int i=head[x];i;i=edge[i].next){
29         if(f[edge[i].to]) 
30             continue;
31         if(dfn[edge[i].to])
32             low[x]=min(low[x],dfn[edge[i].to]); 
33         else{ 
34             dfs(edge[i].to);
35             low[x]=min(low[x],low[edge[i].to]);
36         }
37     }
38     if(low[x]==dfn[x]){
39         ++ans2;
40         while(p.top()!=x){
41             f[p.top()]=1; 
42             printf("%d ",p.top()); 
43             place[p.top()]=ans2; 
44             p.pop(); 
45             k=1;
46         }
47         f[p.top()]=1;
48         place[p.top()]=ans2;
49         p.pop();
50         printf("%d\n",x);
51         if(k)++ans1;
52     }
53 }
54 int main(){
55     scanf("%d%d",&n,&m); 
56     for(int i=1;i<=n;i++)
57         f[i]=0;
58     for(int i=1;i<=m;i++){
59         scanf("%d%d",&x,&y);
60         add_edge(x,y); 
61     }
62     for(int i=1;i<=n;i++)
63         if(dfn[i]==0){ 
64             time=0; 
65             dfs(i);
66         }
67     printf("%d\n",ans1); 
68     printf("%d\n",ans2); 
69     for(int i=1;i<=n;++i)
70         printf("%d ",place[i]); 
71     return 0;
72 }
View Code

 

posted @ 2017-04-14 16:44  江屿  阅读(481)  评论(2编辑  收藏  举报