话说昨天练习的时候,有一道题是要求强连通分量预处理的。然而那时我还不知道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。
时间: 2024-10-05 05:07:27