Tarjan算法

Tarjan算法是由Robert Tarjan发明的求有向图中强连通分量的算法。


 

强连通:

  • 如果两个顶点可以相互通达,则称两个顶点 强连通(strongly connected)。如果有向图G的每两个顶点都 强连通,称G是一个强连通图。非 强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components)。

其中有两个很重要的数组:dfn[ ] ,low[ ]

  • dfn[ ]:就是一个时间戳(被搜到的次序),一旦某个点被DFS到后,每个点只有唯一的时间戳。所以常根据dfn的值来判断是否需要进行进一步的深搜,应该是一个flag。

  • low[ ]:该子树中,且仍在栈中的最小时间戳,像是确立了一个关系,low[ ]相等的点在同一强连通分量中。

  • 每次Tarjan前需:dfn[ ] = low[ ] = ++cnt.


 

  • 算法思路:

  •  这个图不一定是一个连通图,所以跑Tarjan前要枚举每个点,若dfn[ ] == 0,进行深搜。

  • 然后对于搜到的点寻找与其有边相连的点,判断这些点是否已经被搜索过,若没有,则进行搜索。若该点已经入栈,说明形成了环,则更新low.

  • 遍历,存边可以用前向星。

struct edge{
    int to;
    int nxt;
}e[N];
int head[N];
......
for(int i=1,x,y;i<=n;i++)
{
    scanf("%d%d",&x,&y);
    e[++tot].to=y;
    e[tot].nxt=head[x];
    head[x]=tot;
}
前向星
  • 在不断深搜的过程中如果遍历完了,那么就进行回溯,回溯时不断比较low[ ],去最小的low值。如果dfn[x]==low[x], 即搜到一个出度为零的点,则x可以看作是某一强连通分量子树的根,也说明找到了一个强连通分量,然后对栈进行弹出操作,直到x被弹出。这样我们就找到了一个强连通分量。

  • 一个板子...

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 vector <int>v[10002];
 4 stack <int>stk;
 5 int dfn[10002],ans,low[10002],dd;
 6 bool vis[10002];
 7 struct edge{
 8 int nxt;
 9 int to;
10 }e[50002];int head[50002];
11 int min(int a,int b){return a>b?b:a;}
12 void tarjan(int u)
13 {
14     dfn[u]=low[u]=++dd;
15     stk.push(u);
16     vis[u]=true;
17     for(int i=head[u];i;i=e[i].nxt)
18     {
19         int temp=e[i].to;
20         if(!dfn[temp])
21         {
22             tarjan(temp);
23             low[u]=min(low[u],low[temp]);
24         }
25         else if(vis[temp])low[u]=min(low[u],dfn[temp]);
26     }
27     if(dfn[u]==low[u])
28     {
29         int s,tmp=0;
30         do{
31             s=stk.top();
32             stk.pop();
33             tmp++;
34 //          cout<<s<<" ";
35             vis[s]=false;
36         }while(u!=s);
37 //      cout<<endl;
38         if(tmp>1)ans++;
39     }
40 }
41 int main()
42 {
43     int n,m;
44     scanf("%d%d",&n,&m);
45     int tot=0;
46     for(int i=1,a,b;i<=m;i++)
47     {
48         scanf("%d%d",&a,&b);
49         v[a].push_back(b);
50         e[++tot].to=b;
51         e[tot].nxt=head[a];
52         head[a]=tot;
53     }
54     for(int i=1;i<=n;++i)
55     {
56         if(!dfn[i]) tarjan(i);
57     }
58     printf("%d\n",ans);
59 }
Tarjan Code
  • Tarjan求LCA我会在后面的帖子给大家。
  • Are you clear?qaq

posted @ 2019-07-26 19:43  milkitblogcn  阅读(199)  评论(0编辑  收藏  举报