【学习】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。

时间: 2024-10-05 05:07:27

【学习】tarjan算法的相关文章

对求有向图强连通分量的tarjan算法原理的一点理解

先简单叙述一下tarjan算法的执行过程(其他诸如伪代码之类的相关细节可以自己网上搜索,这里就不重复贴出了): 用到两类数组: dfs[]:DFS过程中给定节点的深度优先数,即该节点在DFS中被访问的次序 low[]:从给定节点回溯时,节点的low值为从节点在DFS树中的子树中的节点可以回溯到的栈中DFS值最小的节点的dfs值 一个数据结构:栈,用于确定强连通分量 执行过程:对有向图进行深度优先搜索,每抵达一个新节点A就把该节点A入栈,并初始化dfs[A],然后将low[A]初始化为dfs[A]

hdu 1269 迷宫城堡 (tarjan算法学习)

迷宫城堡 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 7056    Accepted Submission(s): 3137 Problem Description 为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A

Tarjan算法学习笔记

一种由Robert Tarjan提出的求解有向图强连通分量的线性时间的算法. [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components). 下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达.{5},{6}也分别是两个强连通分量. 直接根据

【转】BYV--有向图强连通分量的Tarjan算法

转自beyond the void 的博客: https://www.byvoid.com/zhs/blog/scc-tarjan 注:红色为标注部分 [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components). 下图中,子图{1,2,3,4}为一个强连通分量,因为顶

TarJan 算法求解有向连通图强连通分量

[有向图强连通分量] 在有向图G中,如果两个 顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components). 下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达.{5},{6}也分别是两个强连通分量. 大体来说有3中算法Kosaraju,Trajan,Gabow这三种!后续文章中将相继

Tarjan算法详解

Tarjan算法详解 [概念] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components). 下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达.{5},{6}也分别是两个强连通分量. [功能] Tarjan算法的用途之一是,求一个有向图G=(V,E)里极大强连

【转载】有向图强连通分量的Tarjan算法

from byvoid [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components). 下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达.{5},{6}也分别是两个强连通分量. 直接根据定义,用双向遍历取交集的方法求强连通分量,时间复杂度为

有向图强连通分量的Tarjan算法(转)

原文地址:有向图强连通分量的Tarjan算法 [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components). 下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达.{5},{6}也分别是两个强连通分量. 直接根据定义,用双向遍历取交集的方法求强

有向图强连通分量的Tarjan算法——转自BYVoid

[有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components). 下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达.{5},{6}也分别是两个强连通分量. 直接根据定义,用双向遍历取交集的方法求强连通分量,时间复杂度为O(N^2+M).更好的