Tarjan

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 const int MAXN=100010;
 6 const int MAXM=100010;
 7 
 8 struct Edge
 9 {
10     int to,next,w;
11 }e[MAXM*2];
12 int head[MAXN];
13 
14 int cnt=0;
15 void addEdge(int x,int y,int z=1)
16 {
17     cnt++;
18     e[cnt].next=head[x];
19     e[cnt].to=y;
20     e[cnt].w=z;
21     head[x]=cnt;
22     return;
23 }
24 
25 int tot=0;   //时间
26 int dfn[MAXN],low[MAXN];   //dfn-记录时间戳,low-根
27 int s[MAXN],idx=0;   //栈数组,下标
28 bool instack[MAXN];   //是否在栈中
29 void tarjan(int x)   //tarjan算法,实际上是一个dfs递归的过程
30 {
31     dfn[x]=low[x]=++tot;   //更新时间戳和连通子图的根
32     s[++idx]=x;   //进栈
33     instack[x]=true;   //标记为在栈中
34     for (int i=head[x];i!=0;i=e[i].next)   //遍历每条边的另一端(终点)
35     {
36         int j=e[i].to;   //终点
37         if (!dfn[j])   //没访问过
38         {
39             tarjan(j);   //继续dfs
40             low[x]=min(low[x],low[j]);   //更新根
41         }
42         else if (instack[j])   low[x]=min(low[x],low[j]);   //访问过且在栈中,更新根
43         //如果访问过且不在栈中,则说明已经形成一个连通子图
44     }
45     if (dfn[x]==low[x])   //时间戳和根相等,说明是根
46     {
47         do
48         {
49             cout<<s[idx]<<" ";
50             instack[s[idx]]=false;
51             idx--;
52         }while (x!=s[idx+1]);   //出栈并输出
53         cout<<endl;
54     }
55     return;
56 }
57 
58 int main()
59 {
60     int n,m;
61     cin>>n>>m;
62     int u,v;
63     for (int i=1;i<=m;i++)
64     {
65         cin>>u>>v;
66         addEdge(u,v);
67     }
68     for (int i=1;i<=n;i++)
69     {
70         if (!dfn[i]) tarjan(i);   //没有时间戳,说明未访问过,则遍历,防止图没走完
71     }
72 
73     return 0;
74 }

 

上一篇:tarjan法求LCA学习笔记


下一篇:初见 | 图论 | Tarjan