学习tarjan算法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习tarjan算法相关的知识,希望对你有一定的参考价值。

话说昨天练习的时候,有一道题是要求强连通分量预处理的。然而那时我还不知道tarjan算法为何物,于是糊出了如下求强连通分量的算法。(时间复杂度O(n*logn))

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=10010;
 4 struct edge{
 5     int la,b;
 6 }con[N<<1];
 7 int tot,fir[N];
 8 void add(int u,int v)
 9 {
10     con[++tot].la=fir[u];
11     con[tot].b=v;
12     fir[u]=tot;
13 }
14 int deep[N],bel[N],n,m;
15 bool pass[N],vis[N];
16 int get_bel(int pos)
17 {
18     if(bel[pos]!=pos) bel[pos]=get_bel(bel[pos]);
19     return bel[pos];
20 }
21 int dfs(int pos,int fa)
22 {
23     vis[pos]=1;pass[pos]=1;
24     deep[pos]=deep[fa]+1;
25     bel[pos]=pos;
26     int tmp;
27     for(int i=fir[pos];i;i=con[i].la)
28     {
29         if(vis[con[i].b]&&!pass[con[i].b])
30         {
31             if(pass[get_bel(con[i].b)])
32             {
33                 if(deep[get_bel(con[i].b)]<deep[get_bel(pos)])
34                  bel[pos]=get_bel(con[i].b);
35             }
36             continue;
37         }
38         if(!pass[con[i].b])
39         {
40             tmp=dfs(con[i].b,pos);
41             if(pass[tmp]&&deep[tmp]<deep[get_bel(pos)]) bel[pos]=tmp;
42         }
43         else
44         {
45             if(deep[con[i].b]<deep[get_bel(pos)]) bel[pos]=con[i].b;
46         }
47     }
48     pass[pos]=0;
49     return get_bel(pos);
50 }
51 void solve()
52 {
53     dfs(1,0);
54     for(int i=1;i<=n;i++) cout<<get_bel(i)<<endl;
55 }
56 int main()
57 {
58     int from,to;
59     scanf("%d%d",&n,&m);
60     for(int i=1;i<=m;i++)
61     {
62         scanf("%d%d",&from,&to);
63         add(from,to);
64     }
65     solve();
66     return 0;
67 }

于是用这个算法写了那道题,居然AC了。(那题还要求单源最短路,卡不掉我的O(n*logn)预处理2333)

(注:这个辣鸡算法就是用并查集把每一个点连向其所在强联通分量的深度最小的点,再对树边,后向边,横叉边都讨论一遍(前向边当横叉边处理))

然后我又学了tarjan算法,便又写了如下程序。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=10010;
 4 int low[N],dfn[N],n,m;
 5 struct edge{
 6     int la,b;
 7 }con[N<<1];
 8 int tot,fir[N];
 9 void add(int from,int to)
10 {
11     con[++tot].la=fir[from];
12     con[tot].b=to;
13     fir[from]=tot;
14 }
15 stack<int>s;
16 int bel[N],cnt;
17 void tarjan(int pos)
18 {
19     s.push(pos);
20     low[pos]=dfn[pos]=++cnt;
21     for(int i=fir[pos];i;i=con[i].la)
22     {
23         if(bel[con[i].b]) continue;
24         if(!dfn[con[i].b]) tarjan(con[i].b);
25         low[pos]=min(low[pos],low[con[i].b]);
26     }
27     if(dfn[pos]==low[pos])
28     {
29         int po=s.top();s.pop();
30         while(po!=pos)
31         {
32             bel[po]=pos;
33             po=s.top();s.pop();
34         }
35         bel[pos]=pos;
36     }
37 }
38 void solve()
39 {
40     while(!s.empty()) s.pop();
41     tarjan(1);
42     for(int i=1;i<=n;i++) cout<<bel[i]<<endl;
43 }
44 int main()
45 {
46     int from,to;
47     scanf("%d%d",&n,&m);
48     for(int i=1;i<=m;i++)
49     {
50         scanf("%d%d",&from,&to);
51         add(from,to);
52     }
53     solve();
54     return 0;
55 }

短了很多。

然后就没有然后了。(tarjan算法的解析?网上多着呢。)

 

小结:大佬与蒟蒻的差距就体现在那个log。

以上是关于学习tarjan算法的主要内容,如果未能解决你的问题,请参考以下文章

学习:Tarjan算法

Tarjan算法学习笔记

tarjan算法求强联通分量

Tarjan算法总结

Tarjan各大算法汇总

机器学习实战应用案例100篇(二十五)-强联通分量算法应用案例