標籤:深度 解析 ret 強連通 強聯通 top 沒有 space blog
話說昨天練習的時候,有一道題是要求強連通分量預先處理的。然而那時我還不知道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 else44 {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演算法