算法模板——Tarjan强连通分量

功能:输入一个N个点,M条单向边的有向图,求出此图全部的强连通分量

原理:tarjan算法(百度百科传送门),大致思想是时间戳与最近可追溯点

这个玩意不仅仅是求强连通分量那么简单,而且对于一个有环的有向图可以有效的进行缩点(每个强连通分量缩成一个点),构成一个新的拓扑图(如BZOJ上Apio2009的那个ATM)(PS:注意考虑有些图中不能通过任意一个单独的点到达全部节点,所以不要以为直接tarjan(1)就了事了,还要来个for循环,不过实际上复杂度还是O(M),因为遍历过程中事实上每个边还是只会被走一次^_^)

 1 type
 2     point=^node;
 3     node=record
 4                g:longint;
 5                next:point;
 6     end;
 7
 8 var
 9    i,j,k,l,m,n,h,t,ans:longint;
10    ss,s:array[0..100000] of boolean;
11    low,dfn,b,f:array[0..100000] of longint;
12    a:array[0..100000] of point;
13    p:point;
14 function min(x,y:longint):longint;inline;
15          begin
16               if x<y then min:=x else min:=y;
17          end;
18 function max(x,y:longint):longint;inline;
19          begin
20               if x>y then max:=x else max:=y;
21          end;
22 procedure add(x,y:longint);inline;
23           var p:point;
24           begin
25                new(p);
26                p^.g:=y;
27                p^.next:=a[x];
28                a[x]:=p;
29           end;
30 procedure tarjan(x:longint);
31           var i,j,k:longint;p:point;
32           begin
33                inc(h);low[x]:=h;dfn[x]:=h;
34                inc(t);f[t]:=x;s[x]:=true;ss[x]:=true;
35                p:=a[x];
36                while p<>nil do
37                      begin
38                           if not(s[p^.g]) then
39                              begin
40                                   tarjan(p^.g);
41                                   low[x]:=min(low[x],low[p^.g]);
42                              end
43                           else if ss[p^.g] then low[x]:=min(low[x],dfn[P^.g]);
44                           p:=p^.next;
45                      end;
46                if low[x]=dfn[x] then
47                   begin
48                        inc(ans);
49                        while f[t+1]<>x do
50                              begin
51                                   ss[f[t]]:=false;
52                                   b[f[t]]:=ans;
53                                   dec(t);
54                              end;
55                   end;
56           end;
57 begin
58      readln(n,m);
59      for i:=1 to n do a[i]:=nil;
60      for i:=1 to m do
61          begin
62               readln(j,k);
63               add(j,k);
64          end;
65      fillchar(s,sizeof(s),false);
66      fillchar(ss,sizeof(ss),false);
67      fillchar(f,sizeof(f),0);
68      fillchar(low,sizeof(low),0);
69      fillchar(dfn,sizeof(dfn),0);
70      fillchar(b,sizeof(b),0);
71      for i:=1 to n do
72          if s[i]=false then tarjan(i);
73      for i:=1 to n do a[i]:=nil;
74      for i:=1 to n do add(b[i],i);
75      for i:=1 to ans do
76          begin
77               p:=a[i];
78               write(‘No. ‘,i,‘ :‘);
79               while p<>nil do
80                     begin
81                          write(‘ ‘,p^.g);
82                          p:=p^.next;
83                     end;
84               writeln;
85          end;
86      readln;
87 end.
88              
时间: 2024-10-17 12:53:00

算法模板——Tarjan强连通分量的相关文章

『Tarjan算法 有向图的强连通分量』

有向图的强连通分量 定义:在有向图\(G\)中,如果两个顶点\(v_i,v_j\)间\((v_i>v_j)\)有一条从\(v_i\)到\(v_j\)的有向路径,同时还有一条从\(v_j\)到\(v_i\)的有向路径,则称两个顶点强连通(strongly connected).如果有向图\(G\)的每两个顶点都强连通,称\(G\)是一个强连通图.有向图的极大强连通子图,称为强连通分量(strongly connected components). 万能的Tarjan算法也可以帮助我们求解有向图的强

hdu1269 Tarjan强连通分量 模板(转)

#include<stdio.h> #include<iostream> #include<vector> using namespace std; const int maxn=10010; vector<int>g[maxn]; int Bcnt; int Top; int Index; int low[maxn],dfn[maxn]; int belong[maxn],stack[maxn]; int instack[maxn]; void Init_

Tarjan算法求有向图强连通分量并缩点

// Tarjan算法求有向图强连通分量并缩点 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<queue> using namespace std; const int N = 100010, M = 1000010; // int ver[M], Next[M], head[N],

tarjan 强连通分量

一.强连通分量定义 有向图强连通分量在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(stronglyconnected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.有向图的极大强连通子图,称为强连通分量(stronglyconnectedcomponents)SCC. 以上是摘自百科的一段对有向图强连通图分量的形式化定义.其实不难理解,举个例子 如上图,{a,b,c,d}为一个强连通分量,{e}

poj2186Popular Cows(Kosaraju算法--有向图的强连通分量的分解)

1 /* 2 题目大意:有N个cows, M个关系 3 a->b 表示 a认为b popular:如果还有b->c, 那么就会有a->c 4 问最终有多少个cows被其他所有cows认为是popular! 5 6 思路:强连通分量中每两个节点都是可达的! 通过分解得到最后一个连通分量A, 7 如果将所有的强连通分量看成一个大的节点,那么A一定是孩子节点(因为我们先 8 完成的是父亲节点的强连通分量)! 最后如果其他的强连通分量都可以指向A,那么 9 A中的每一个cow都会被其他cows所

【模板】强连通分量和tarjan算法

看了好久才终于明白了这个算法..复杂度是O(n+m). 我觉得这个算法不是很好理解,但是看懂了以后还是觉得听巧妙的. 下面给出模板代码和三组简单数据帮助理解. 代码如下: 1 #include <stdio.h> 2 #include <stack> 3 #include <algorithm> 4 #include <string.h> 5 #include <vector> 6 using namespace std; 7 8 const i

Tarjan——强连通分量

是的你没有看错,又是Tarjan(说过他发明了很多算法),那么什么是Tarjan 首先看看度娘的解释: 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.有向图的极大强连通子图,称为强连通分量(strongly connected components). 是不是没有看懂,我也是 首先了解几个概念:

POJ1236 (Network of Schools,Tarjan,强连通分量)

转载自:http://www.tuicool.com/articles/EnMFFja 原创:kuangbin 题意:  一个有向图,求: 1) 至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点 2) 至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点,即成为一个强连通分量 思路: 求完强连通分量后,缩点,计算每个点的入度,出度. 第一问的答案就是入度为零的点的个数, 第二问就是max(n,m)  入度为零的个数为n, 出度为零的个数为m 思路详解: 1. 求出所有强连通分

图论算法之(强连通分量&lt;Kosaraju&gt;)

强连通分量算法有3个之多,现在介绍这种名字叫做kosaraju算法. 这个算法基于两个事实,1.原图G与逆置图GT拥有相同的强连通分量,这肯定是正确的 2.任意一个子节点存放皆后于父节点,也就是说所有只有当所有子节点都入栈了,父节点才入栈 这种在递归调用之后将顶点入队列的方式叫逆后续排序(reverse post),在无环图中这种排序方式就是拓扑排序. 简要证明: 1. 第一次DFS有向图G时,最后记录下的节点必为最后一棵生成树的根节点. 证明:假设最后记录下节点不是树根,则必存在一节点为树根,