tarjan算法其实是在dfs基础上维护一个标志值来判断当前点是否是某种特殊点,而学习tarjan算法,通过tarjan的DEPTH-FIRST SEARCH AND LINEAR GRAPH ALGORITHMS学习好像并不是什么好的选择…但是读一读dalao的论文还是挺有趣的,本文对tarjan的论文进行简单翻译和补充我自己的理解。

一些符号和基础定义:
对于图G=(V,E)G=(V,E)G=(V,E)来说。
路径p:v⇒∗wp:v\stackrel{*}{\Rightarrow}wp:v⇒∗w表示存在一个从vvv到www的点和边的序列。
如果一条路径上所有的点都互不相同,则我们称其为简单路径(simple path)。
路径p:v⇒∗vp:v\stackrel{*}{\Rightarrow}vp:v⇒∗v是一个闭合回路(closed path)。
一个闭合回路p:v⇒∗vp:v\stackrel{*}{\Rightarrow}vp:v⇒∗v如果它的所有边各不相同,并且在ppp中只有vvv出现了两次,那么我们称p为一个环(cycle)。
如果两个环它们的循环排列互相相同,那么我们把两个环视为同一个环。
如果无向图中所有的点对之间都有一条路径,那么它是连通的(connected)。

对于一棵(有向根)树TTT来说。
无向版本的TTT是连通的,并且有一个根节点它不是任何边的终点(head),而除了根节点外的所有点都是且只是某一条边的终点。
v→wv\rightarrow wv→w表示"(v,w)(v,w)(v,w)是TTT中的一条边"。
v→∗wv\stackrel{*}{\rightarrow}wv→∗w表示"在TTT中存在一条从vvv到www的路径"。
如果v→wv\rightarrow wv→w,那么vvv是www的父节点(father),www是vvv的子节点(son)。
如果v→∗wv\stackrel{*}{\rightarrow}wv→∗w,那么vvv是www的祖先节点(ancestor),www是vvv的后代节点(descendant)。
每个点都是自己的祖先节点和后代节点。
如果vvv是TTT中的一个点,那么TvT_vTv​是由vvv的所有后代节点组成的"TTT的子树"。
如果GGG是一个有向图,如果树TTT包含GGG中所有的点并且TTT是GGG的子图,那么TTT是GGG的一个生成树。

定义1: G=(V,E)G=(V,E)G=(V,E)是一个图,对于每个点v∈Vv\in Vv∈V我们可以构造一个包含所有的有(v,w)∈E(v,w)\in E(v,w)∈E的点www组成的列表,我们称这样的列表为vvv的邻接表; 对于图GGG的所有点的邻接表构成的集合,我们称之为图GGG的邻接结构。

这就是我们熟悉的邻接表,没什么好说的。

定义2: 设PPP是一个有向图,它的边集由两个不相交的集合组成,分别用v→wv\rightarrow wv→w和v⇢wv\dashrightarrow wv⇢w表示其中的边,假定P满足以下性质:
  (i) 包含v→wv\rightarrow wv→w的边构成的子图TTT是PPP的一棵生成树。
  (ii) ⇢⊆(→∗)−1\dashrightarrow \subseteq (\stackrel{*}{\rightarrow}) ^{-1}⇢⊆(→∗)−1,简单来说如果有u⇢vu\dashrightarrow vu⇢v,那么一定有v→∗uv \stackrel{*}{\rightarrow} uv→∗u,对于所有P中没有在T中的边,都把某个点连接到了它在T中某个祖先节点上。
那么PPP就是一个palm树,我们把所有v⇢wv\dashrightarrow wv⇢w这样的边称为PPP的frondfrondfrond。

我们可以看到palm树只有祖先和后代之间可能有边,借助这一性质可以帮助我们完成很多事情。

定理1: PPP是无向连通图GGG通过dfs生成的有向图,那么PPP是一棵palm树; 相反地,任何palm树PPP都可以由无向版本的PPP通过dfs得来。

我们定义palm树这样的结构就是为了和dfs建立联系,下面我们给出一种构造的算法。

算法1:

BEGININTEGER i;PROCEDURE DFS(v, u); COMMENT vertex u is the father ofvertex v in the spanning tree being constructed;BEGINNUMBER(v) := i := i+1;FOR w in the adjacency list of v DOBEGINIF w is not yet numbered THENBEGINconstruct arc $v->w$ in P;DFS(w, v);ENDELSE IF NUMBER(w) < NUMBER(v) and w != uTHEN construct arc $v-->w$ in P;END;END;i := 0;DFS(s, 0);
END;

需要注意NUMBER(w)<NUMBER(v)NUMBER(w)<NUMBER(v)NUMBER(w)<NUMBER(v)是必要的条件,避免祖先再沿着frondfrondfrond的反向指向后代。关于这个构造的正确性,因为它本身是不反直觉的,所以我只说下为什么这样构造出来的frondfrondfrond都是指向祖先的。如果(v,w)(v,w)(v,w)中www已经被number了,那么它有两种情况,一种是NUMBER(v)<NUMBER(w)NUMBER(v)<NUMBER(w)NUMBER(v)<NUMBER(w),一种是NUMBER(v)>NUMBER(w)NUMBER(v)>NUMBER(w)NUMBER(v)>NUMBER(w)。
  我们先看NUMBER(v)>NUMBER(w)NUMBER(v)>NUMBER(w)NUMBER(v)>NUMBER(w),如果www不是vvv的父亲的话,我们有(v,w)(v,w)(v,w)一定早于(w,v)(w,v)(w,v)被检查(不然www就是vvv的父亲),但是www比vvv先被number,所以唯一的可能是www还没有从DFS(w,−)DFS(w,-)DFS(w,−)中返回,那么显然vvv是www的后代,这就是我们添加进的frondfrondfrond。
  我们再看另一种情况,这里的www比vvv晚number,但是我们还在DFS(v,−)DFS(v,-)DFS(v,−)中,所以显然www是vvv已经返回的后代,这种情况下我们在DFS(w,−)DFS(w,-)DFS(w,−)中已经有了frondfrondfrond (w,v)(w,v)(w,v),所以这种情况我们会进行丢弃。

推论2: 任何无向图GGG都可以通过把边以适当的方式有向化转换为一个palm树。

其实就是定理1的另一种说法。

定义3: G=(V,E)G=(V,E)G=(V,E)是一个无向图。对于VVV中任意互不相同三点vvv,www,aaa,存在一条路径p:v⇒∗wp:v\stackrel{*}{\Rightarrow}wp:v⇒∗w不经过aaa,那么GGG是点双连通的。另一方面如果VVV中存在互不相同的三点vvv,www,aaa,有aaa总是在任何p:v⇒∗wp:v\stackrel{*}{\Rightarrow}wp:v⇒∗w的路径上,且最少存在一条路径,那么aaa就是图GGG的割点。

引理3: 无向图G=(V,E)G=(V,E)G=(V,E),我们定义一种在边集中的等价关系: 当且仅当两边属于同一个环时,两边是等价的。我们让不同的等价类分别为EiE_iEi​,1≦i≦n1\leqq i\leqq n1≦i≦n,并且Gi=(Vi,Ei)G_i=(V_i, E_i)Gi​=(Vi​,Ei​),ViV_iVi​是EiE_iEi​中的点的集合; Vi=v∣∃w((v,w)∈Ei)V_i={ v| \exists w((v, w)\in E_i)}Vi​=v∣∃w((v,w)∈Ei​),那么:
  (i) 对于每个1≦i≦n1\leqq i\leqq n1≦i≦n,GiG_iGi​是点双连通的。
  (ii) 没有GiG_iGi​是GGG的某个点双连通子图的真子图。
  (iii) 图GGG的每个割点在所有Vi(1≦i≦n)V_i (1\leqq i\leqq n)Vi​(1≦i≦n)中一共至少出现两次。图GGG的每个非割点在所有Vi(1≦i≦n)V_i (1\leqq i\leqq n)Vi​(1≦i≦n)中一共出现且只出现一次。
  (iv) 对于任意的1≦i,j≦n1\leqq i,j\leqq n1≦i,j≦n,Vi∩VjV_i\cap V_jVi​∩Vj​至多只包含一个点,且这个点是图的割点。
那么图GGG的子图GiG_iGi​被叫做GGG的点双连通分量。

我们给出了割点的定义和点双连通分量的定义,为了便于寻找点双连通分量,我们再给出LOWPTLOWPTLOWPT的定义。

LOWPT(v)LOWPT(v)LOWPT(v)是集合{v}∪{w∣v→∗⇢w}\{v\}\cup\{w|v\stackrel{*}{\rightarrow}\dashrightarrow w\}{v}∪{w∣v→∗⇢w}中最小的点。即LOWPT(v)LOWPT(v)LOWPT(v)是最小的从v经过0或更多条树边再加1条frondfrondfrond可达的最小的点。

引理4: 对于无向图GGG,PPP是有向化GGG中的边形成的palm树,TTT是PPP的生成树,假定p:v⇒∗wp:v\stackrel{*}{\Rightarrow}wp:v⇒∗w是在GGG中任意一条这样的路径,那么ppp中包含一个点,且这个点是vvv和www在TTT中的祖先节点。

设以uuu为根的TuT_uTu​是TTT中包含p:v⇒∗wp:v\stackrel{*}{\Rightarrow}wp:v⇒∗w中所有节点最小的子树,如果u=vu=vu=v或是u=wu=wu=w,那么显然。否则我们假设Tu1T_{u_{1}}Tu1​​和Tu2T_{u_{2}}Tu2​​是两棵包含了ppp上点的子树,并且u→u1u\rightarrow u_1u→u1​, u→u2u\rightarrow u_2u→u2​(即u1u_1u1​和u2u_2u2​是uuu的儿子)。如果只有一棵这样的子树,那么由于TuT_uTu​是最小的会使得uuu是路径上的点(反证);如果两棵这样的子树存在,那么路径ppp如果想要从Tu1T_{u_{1}}Tu1​​到Tu2T_{u_{2}}Tu2​​就必须要经过u,因为无论是→\rightarrow→还是⇢\dashrightarrow⇢都与祖先节点相连,而两棵子树中任何点都不可能是另一棵子树中的点的祖先。而uuu是两者所有节点的祖先节点,并且uuu是TuT_uTu​中唯一满足这个条件的点,所以uuu一定会在ppp上。

引理5: 让GGG是一个无向连通图,PPP是有向化GGG中的边后形成的palm树,TTT是PPP的生成树。假定aaa,vvv,www是图GGG中三个不同的点,并且有(a,v)∈T(a,v)\in T(a,v)∈T,www不是vvv在TTT中的后代节点(即在TTT中不存在(v→∗w)(v\stackrel{*}{\rightarrow}w)(v→∗w))。如果LOWPT(v)≧aLOWPT(v)\geqq aLOWPT(v)≧a,那么aaa是GGG的一个割点,并且移除a将导致vvv和www断连。相反地,如果aaa是GGG的一个割点,那么存在点vvv和www满足上述的性质。

如果有a→va\rightarrow va→v,并且LOWPT(v)≧aLOWPT(v)\geqq aLOWPT(v)≧a,那么任何与vvv相关的路径(无论是vvv出发,还是以vvv为终点)如果不经过aaa的话,那么只能在子树TvT_vTv​中,但是这棵子树是没有点www的,第一部分得证。(其实这里一开始我产生了疑问,有向化的palm树没有路径并不能代表GGG没有路径,但是这里把这里的路径想成是无向版本palm树的路径即可)
为了证明逆命题,我们设aaa是图GGG的一个割点。如果aaa是PPP的根,那么就最少有两条树边从aaa发出(不然显然去除aaa不会影响连通性,即与aaa是割点矛盾),我们设有两条边分别为(a,v)(a,v)(a,v)和(a,w)(a,w)(a,w),那么显然LOWPT(v)≧aLOWPT(v)\geqq aLOWPT(v)≧a,并且www也不是vvv的后代;如果aaa不是PPP的根,那么考虑删除aaa后形成图GGG的连通分量,其中某一个连通分量一定只包含aaa的后代(如果没有这样的连通分量,那么由于除去TaT_aTa​即aaa的后代节点外的点的连通性都不受影响,图不会被分割成至少两个连通分量,这与aaa是割点矛盾)(并且这个连通分量只会包含一个aaa的子节点,由引理4,准确来说是类似引理4的证明),我们设vvv是这个连通分量中aaa的子节点,www是vvv的某个真祖先节点,那么我们有a→va\rightarrow va→v,LOWPT(v)≧aLOWPT(v)\geqq aLOWPT(v)≧a(否则vvv就会与aaa的真祖先节点之间可达),www不是vvv的后代节点。因此反命题得证。
这里的证明很重要,它使得"aaa有子节点v(LOWPT(v)≧a)v(LOWPT(v)\geqq a)v(LOWPT(v)≧a)且存在一个不是vvv的后代节点的点"成为了"aaa是割点"的充要条件,让我们很方便地判断一个点是否是割点。

推论6: GGG是连通无向图,PPP是有向化GGG的边后形成的palm树,TTT是PPP的生成树。如果CCC是GGG中一个点双连通分量,那么CCC中的点组成了TTT中的一棵子树,并且这棵子树的根要么是GGG的割点,要么是TTT的根。

这条推论把找点双连通分量的问题转化为了找割点的问题。这里我们给出一个更方便计算的LOWPTLOWPTLOWPT的式子,进而给出求点双连通分量的算法。
LOWPT(v)=min({NUMBER(v)}∪{LOWPT(w)∣v→w}∪{NUMBER(w)∣v⇢w})LOWPT(v) = min(\{NUMBER(v)\}\cup\{LOWPT(w)|v\rightarrow w\}\cup\{NUMBER(w)|v\dashrightarrow w\}) LOWPT(v)=min({NUMBER(v)}∪{LOWPT(w)∣v→w}∪{NUMBER(w)∣v⇢w})

算法2:

BEGININTEGER i;procedure BICONNECT(v, u);BEGINNUMBER(v) := i := i+1;LOWPT(v) := NUMBER(v);FOR w in the adjacency list of v DOBEGINIF w is not yet numbered THENBEGINadd (v, w) to stack of edges;BICONNECT(w, v)LOWPT(v) := min(LOWPT(v), LOWPT(w));IF LOWPT(w) >= NUMBER(v) THENBEGINstart new biconnected component;WHILE top edge e = (u1, u2) on edgestack has NUMBER(u1)>= NUMBER(w) DOdelete(u1, u2) from edge stack andadd it to current component;delete (v, w) from edge stack and addit to current component;END;ENDELSE IF (NUMBER(w) < NUMBER(v)) and (w != u) THENBEGINadd (v, w) to edge stack;LOWPT(v) := min(LOWPT(v), NUMBER(w));END;END;END;i:=0;empty the edge stack;FOR w a vertex DO IF w is not yet numbered THEN BICONNECT(w, 0);
END;

定理7: 该点双连通算法对于一个有VVV个点EEE条边的图需要O(V,E)O(V,E)O(V,E)的空间和时间。

这里的过程其实和前面的dfs别无二致,而这里的额外操作与EEE成比例,palm树上每条边都最多会入栈一次,所以显然。

定理8: 该点双连通分量算法对于任何无向图都可以正确给出所有的点双连通分量。

因为dfs的过程其实是对每个连通分量进行分析的,所以我们只需要证明连通图中的正确性即可。
我们用归纳证明。
当连通图GGG中没有边时,即GGG是空图或是只有1个点时。这个算法会正确地终止,并且列出没有点双连通分量,显然这种情况下它是正确的。
假定算法在连通图的边数小于等于E−1E-1E−1时会得到正确结果,我们把算法应用到一个有EEE条边的连通图GGG上。
  我们假设我们应用算法时会跑出来至少两个点双连通分量,我们设第一个点双连通分量为G′G'G′,显然当G′G'G′的边数小于EEE,那么我们可以先只用G′G'G′中的点和边,从其中NUMBERNUMBERNUMBER最小的点即G′G'G′的根节点出发,然后再把GGG中所有G′G'G′中除了G′G'G′的根节点以外的点及对应的边都删去,再从原本的根节点出发,这样我们会有和直接从根节点出发完全相同的结果,并且由边数小于EEE情况下结果是正确的保证正确性。(其实这里有着问题,对两个子图正确,不代表对子图合起来的图正确,但是我们知道G′G'G′的根节点是割点,那么一定有一个只包含它后代节点的点双连通分量,而G′G'G′就是这样的一个分量,补上这样的描述应该就够了)
  我们接下来证明只有一个连通分量的情况下它是正确的,首先除了根节点以外的节点都不是割点这点已经由引理5保证了。我们用反证法,如果根节点是割点,那么它一定至少有两个子节点(不然不能满足引理5),但是我们知道算法运行时在检查根节点和子节点相连的那条边时,一定会生成一个新的连通分量。这与我们只有一个连通分量矛盾,故根节点也不是割点,即GGG是一个点双连通图。
综上得证。
tarjan这里的证明说实话巧妙得有点让人有点难以接受,但是它确实应该是正确的。

定义4: 有向图GGG,如果对于GGG中任何点对v,wv,wv,w都存在路径p1:v⇒∗wp_1:v\stackrel{*}{\Rightarrow}wp1​:v⇒∗w和p2:w⇒∗vp_2:w\stackrel{*}{\Rightarrow}vp2​:w⇒∗v,那么我们称图GGG是强连通的。

就是最普通的强连通图(strongly connected graph)定义。

引理9: 有向图G=(V,E)G=(V,E)G=(V,E),我们定义点集上的一种等价关系: 对于点vvv和点www,若存在一条包含有www的路径p:v⇒∗vp:v\stackrel{*}{\Rightarrow}vp:v⇒∗v,那么我们称vvv和www是等价的。我们可以VVV中的不同的等价类为Vi(1≦i≦n)V_i(1\leqq i\leqq n)Vi​(1≦i≦n)。Gi=(Vi,Ei)G_i = (V_i,E_i)Gi​=(Vi​,Ei​),Ei={(v,w)∈E∣v,w∈Vi}E_i =\{(v,w)\in E|v,w\in V_i\}Ei​={(v,w)∈E∣v,w∈Vi​}。那么:
  (i) 每个GiG_iGi​都是强连通的。
  (ii) 没有GiG_iGi​是某个强连通图的真子图。
那么我们称这些GiG_iGi​为GGG的强连通分量。

也是普通的强连通分量(strongly connected component)定义。

我们会注意到在有向图中,我们的得力助手palm树不见了…但是也并不是什么限制都没有的。在有向图中,除了树边、frondfrondfrond外,又新出现了一种cross−linkcross-linkcross−link,即从某棵子树中的点指向另一棵子树中的某个点的边。除了上述这些边以外的边,如重边或是指向非子节点的后代节点的边,不会改变两点之间有没有路径的事实,所以我们丢弃。

我们很容易会发现任何cross−linkcross-linkcross−link (v,w)(v,w)(v,w)都具有着NUMBER(v)>NUMBER(w)NUMBER(v)>NUMBER(w)NUMBER(v)>NUMBER(w)的性质(类似前面,我们现在在DFS(v,−)DFS(v,-)DFS(v,−)中,所以如果NUMBER(v)<NUMBER(w)NUMBER(v)<NUMBER(w)NUMBER(v)<NUMBER(w),那么www一定是在DFS(v,−)DFS(v,-)DFS(v,−)中被NUMBERNUMBERNUMBER的,即www是vvv的某个已经返回的后代节点,这是我们前述说的丢弃的边)。我们还可以有进一步的结论,在一串树边后的cross−linkcross-linkcross−link指向某个"不在以起点为根的子树上"的点的NUMBERNUMBERNUMBER一定小于起点的NUMBERNUMBERNUMBER,方法是类似的,因为检查这条cross−linkcross-linkcross−link时我们起点的DFSDFSDFS还没有返回,所以此时任何比它大的NUMBERNUMBERNUMBER都一定是后代节点,故而矛盾。

引理10: 图GGG中的点vvv和点www在同一个强连通分量中,FFF是GGG通过dfs得到的生成树森林。那么vvv和www在FFF中有一个公共的祖先。更进一步的,如果uuu是vvv和www的标号最大的祖先(即lca),那么uuu和vvv以及www在同一个强连通分量中。

不妨令v<wv< wv<w,ppp是vvv到www的路径,假设TxT_xTx​是在FFF中最小的包含ppp中所有点的根为xxx的子树。TxT_xTx​是一定存在的,因为ppp只可能从一棵子树前往一棵有着更小NUMBERNUMBERNUMBER的子树,而不可能前往一棵有着更大NUMBERNUMBERNUMBER的子树(这几个子树互不包含)。如果ppp包含FFF中两棵或更多的树的点,那么它不可能到达www,因为v<wv< wv<w。
因此TxT_xTx​一定存在,进而vvv和www在FFF中有着公共的祖先节点。类似引理4中的证明,如果x=vx=vx=v或x=wx=wx=w那么显然。否则我们假设Tx1T_{x_{1}}Tx1​​和Tx2T_{x_{2}}Tx2​​是两棵包含了ppp上点的子树,并且x→x1x\rightarrow x_1x→x1​, x→x2x\rightarrow x_2x→x2​(即x1x_1x1​和x2x_2x2​是xxx的儿子)。如果只有一棵这样的子树,那么由于TxT_xTx​是最小的,会有xxx一定在ppp上(反证);如果两棵这样的子树存在,因为v<wv< wv<w,所以我们不妨假设x1<x2x_1<x_2x1​<x2​,且ppp第一次离开Tx1T_{x_1}Tx1​​后第一次进入的其他子树是Tx2T_{x_2}Tx2​​,那么路径ppp如果想要离开Tu1T_{u_{1}}Tu1​​只能通过树边或是frondfrondfrond,因为cross−linkcross-linkcross−link只能指向更小的NUMBERNUMBERNUMBER,它不能直接通过cross−linkcross-linkcross−link进入Tx2T_{x_2}Tx2​​,那么ppp上必然有一条指向xxx的边。综上vvv和www的某个公共祖先节点xxx一定在vvv到www的路径ppp上,那么由于www到vvv还存在一条路径,那么xxx、www、vvv一定在同一个SCCSCCSCC中。
设uuu是vvv和www的lca,那么我们有uuu一定在x→∗vx\stackrel{*}{\rightarrow} vx→∗v和x→∗wx\stackrel{*}{\rightarrow} wx→∗w上,进而推出uuu一定和xxx、vvv、www在同一个SCCSCCSCC中。

推论11: CCC是GGG中的一个强连通分量,那么CCC中的点构成了GGG的生成树森林FFF中的某棵树的子树,这棵子树的根我们称之为强连通分量CCC的根。

这个推论和推论6一样,把找SCCSCCSCC转化为了找点是否是SCCSCCSCC的根。根其实就是dfs过程中某个SCCSCCSCC第一个被NUMBERNUMBERNUMBER的点,依次拿去不含其它根的子树,每次拿去的部分就是一个SCCSCCSCC。
说实话LOWPTLOWPTLOWPT的给出已经挺突兀的了,下面的LOWLINKLOWLINKLOWLINK的定义更是突兀,但是这引出了判断一个点是否是SCCSCCSCC根的方法。

LOWLINK(v)=min({v}∪{w∣v→∗⇢w&∃u(u→∗v&u→∗w&u和w在G的同一个强连通分量中)})LOWLINK(v)=min(\{v\}\cup\{w|v\stackrel{*}{\rightarrow}\dashrightarrow w\&\exists u(u\stackrel{*}{\rightarrow}v \& u\stackrel{*}{\rightarrow}w \& u和w在G的同一个强连通分量中)\}) LOWLINK(v)=min({v}∪{w∣v→∗⇢w&∃u(u→∗v&u→∗w&u和w在G的同一个强连通分量中)})

LOWLINK(v)LOWLINK(v)LOWLINK(v)就是与vvv在同一SCCSCCSCC的经0或更多条树边和至多一条frondfrondfrond或cross−linkcross-linkcross−link可达的最小的点。说起来其实非常非常拗口,但是就是这样。

引理12: 我们计算出了有向图GGG中基于GGG的某个通过dfs得到生成树森林FFF的每个点的LOWLINKLOWLINKLOWLINK,则对于任一点vvv当且仅当LOWLINK(v)=vLOWLINK(v)=vLOWLINK(v)=v时,是GGG的某个强连通分量的根。

首先,如果vvv是根的话,那么LOWLINK(v)=vLOWLINK(v)=vLOWLINK(v)=v是显然的,因为如果LOWLINK(v)<vLOWLINK(v)<vLOWLINK(v)<v的话,那么就说明vvv有一个真祖先节点才是根,这与vvv是根矛盾。
然后我们考虑另一方面,我们假定uuu是这个SCCSCCSCC的根,那么由于uuu和vvv在同一个SCCSCCSCC中,所以我们有p:v⇒∗up:v\stackrel{*}{\Rightarrow}up:v⇒∗u,并且vvv在TuT_uTu​上,考虑ppp上第一条不指向TvT_vTv​上的点的边,我们设它指向的是www。这条边要么是frondfrondfrond,要么是cross−linkcross-linkcross−link,但是无论它是什么我们都会有w<vw<vw<v,进而有LOWLINK(v)≦w<vLOWLINK(v)\leqq w<vLOWLINK(v)≦w<v,这与LOWLINK(v)=vLOWLINK(v)=vLOWLINK(v)=v矛盾。
综上,LOWLINK(v)=vLOWLINK(v)=vLOWLINK(v)=v和vvv是某个SCCSCCSCC的根是等价的。

算法3:

BEGININTEGER i;PROCEDURE STRONGCONNECT(v);BEGINLOWLINK(v) := NUMBER(v) := i := i+1;put v on stack of points;FOR w in the adjacency list of v DOBEGINIF w is not yet numbered THENBEGIN COMMENT (v, w) is a tree arc;STRONGCONNECT(w);LOWLINK(v) := min(LOWLINK(v), LOWLINK(w));ENDELSE IF NUMBER(w) < NUMBER(v) DOBEGIN COMMENT (v, w) is a frond or cross-link;if w is on stack of points THENLOWLINK(v) := min(LOWLINK(v), NUMBER(w));END;END;END;IF (LOWLINK(v) = NUMBER(v)) THENBEGIN COMMENT v is the root of a component;start new strongly connected component;WHILE w on top of point stack satisfiesNUMBER(w) >= NUMBER(v) DOdelete w from point stack and put w incurrent componentEND;END;i := 0;empty stack of points;FOR w a vertex IF w is not yet numbered THEN STRONGCONNECT(w);
END;

定理13: 该寻找强连通分量的算法需要O(V,E)O(V,E)O(V,E)的空间和时间。

该算法只是建立在dfs基础上做了一点额外操作。额外操作中每个点最多入栈出栈一次,检查是否在栈中可以用boolean数组来实现,因此会有与VVV和EEE有线性的关系的时间和空间。

定理14: 该寻找强连通分量的算法正确工作在任何有向图GGG中。

这里是我困惑的地方,也是我看着篇论文的最重要原因,但是我没有完全读明白。反复读后,我还是坚持觉得tarjan除了前面画错图外这里的证明也有点问题。所以我准备按照自己的理解来写,各位读者有兴趣的话可以去阅读tarjan的论文,引理14在13页的最下方。

因为判断uuu是否是某个SCCSCCSCC的根节点时,在TuT_uTu​上除了uuu以外的点已经全部返回了,所以如果有根的话,以它为根的子树已经全部出栈了。所以如果这个点是根节点的话,我们只管把栈中所有在根之后入栈的点和根出栈放入同一个SCCSCCSCC中即可。
那么判断我们的算法是否会正确运行,只需要知道判断根节点是否正确即可,即LOWLINKLOWLINKLOWLINK的计算是否正确。
我们还是用归纳法,用比较简单的说法来说,就是假设所有在点vvv结束STRONGCONNECTSTRONGCONNECTSTRONGCONNECT调用前已经结束调用的点的LOWLINKLOWLINKLOWLINK的计算都是正确的;用更直观的说法来说,就是所有{k∣k<v&k不是v的祖先节点}∪{k∣v→∗k}\{k|k<v\& k不是v的祖先节点\}\cup\{k|v\stackrel{*}{\rightarrow} k\}{k∣k<v&k不是v的祖先节点}∪{k∣v→∗k}中的点的LOWLINKLOWLINKLOWLINK都正确计算。(tarjan的说法中没有除去祖先节点,但是事实上,祖先节点的LOWLINKLOWLINKLOWLINK还在计算中,它会正确计算,但是我们此时不知道它是否会正确计算,也不需要它正确计算)
首先我们看第一个返回的点,对于它来说最多只可能有frondfrondfrond来更新LOWLINKLOWLINKLOWLINK。如果它没有frondfrondfrond显然LOWLINKLOWLINKLOWLINK的值正确,否则设∀frond\forall frond∀frond v⇢wv\dashrightarrow wv⇢w,显然∃u(u=w)\exists u(u=w)∃u(u=w)满足我们对LOWLINKLOWLINKLOWLINK更新的条件。
我们再看其他的点,假设在它前面返回的点都正确计算了LOWLINKLOWLINKLOWLINK,即所有{k∣k<v&k不是v的祖先节点}∪{k∣v→k}\{k|k<v\& k不是v的祖先节点\}\cup\{k|v\rightarrow k\}{k∣k<v&k不是v的祖先节点}∪{k∣v→k}中的点都正确计算了LOWLINKLOWLINKLOWLINK。
我们只需要关心v→∗w1⇢w2v\stackrel{*}{\rightarrow} w_1\dashrightarrow w_2v→∗w1​⇢w2​,且w2<vw_2<vw2​<v这样的路径,因为只有这样的路径才有可能更新LOWLINK(v)LOWLINK(v)LOWLINK(v)。(需要注意有可能存在w1=vw_1=vw1​=v)
假设uuu是vvv和w2w_2w2​的lca,那么有两种情况:
  如果uuu和w2w_2w2​不在同一个SCCSCCSCC中,那么在u→∗w2u\stackrel{*}{\rightarrow}w_2u→∗w2​上一定存在一个SCCSCCSCC的根并且那个点不是uuu,由于那个点会在vvv之前返回,所以它的LOWLINKLOWLINKLOWLINK一定会正确计算,那么w2w_2w2​会和它的根一起出栈,因此这种情况我们的算法不会更新LOWLINK(w1)LOWLINK(w_1)LOWLINK(w1​)和LOWLINK(v)LOWLINK(v)LOWLINK(v)(这种情况只会出现在w1⇢w2w_1\dashrightarrow w_2w1​⇢w2​是一条cross−linkcross-linkcross−link的时候)。
  如果uuu和w2w_2w2​在同一个SCCSCCSCC中,那么就满足了我们要求的条件,并且由于uuu还没有返回,根一定是uuu的祖先节点,所以w2w_2w2​一定没有出栈,我们会在LOWLINK(w1)LOWLINK(w_1)LOWLINK(w1​)中更新,进而会更新LOWLINK(v)LOWLINK(v)LOWLINK(v)。
综上我们的算法会正确计算LOWLINKLOWLINKLOWLINK,进而会正确判断根,进而会正确得出所有的SCCSCCSCC。

以上就是tarjan的论文的大多数内容了…说实话知道这种级别的dalao也会犯错误的时候,不知道为什么,还挺开心的(虽然读的时候非常非常非常痛苦…如某个图少一条边…)。

下面是我自己补充的关于割边(边双连通)的内容。

引理15: 对于无向连通图GGG,PPP是有向化GGG中的边后形成的palm树,TTT是PPP的生成树,对于(u,v)∈T(u,v)\in T(u,v)∈T,(u,v)(u,v)(u,v)是割边与LOWPT(v)≧vLOWPT(v) \geqq vLOWPT(v)≧v等价。

首先我们要明白一件事情,就是frondfrondfrond不可能成为割边,这是显然的,所以我们只需要关心TTT中的边。

我们先来证明充分性,如果LOWPT(v)≧vLOWPT(v)\geqq vLOWPT(v)≧v,那么显然从vvv出发的所有路径如果不经过(u,v)(u,v)(u,v),那么终点就只能在TvT_vTv​中。删去(u,v)(u,v)(u,v)会导致uuu和vvv断连,得证。

然后是必要性,(u,v)(u,v)(u,v)是割边,即删去它后导致图不再连通,我们知道删去(u,v)(u,v)(u,v)不会影响TvT_vTv​外的点之间和TvT_vTv​内部之间的连通性,所以必然会形成分别由TvT_vTv​和其他点组成的两个连通分量。即从vvv出发的路径终点只能在TvT_vTv​,即会使得LOWPT(v)≧vLOWPT(v)\geqq vLOWPT(v)≧v,得证。

综上,我们得到了判断一条边是否是割边的充要条件。

写这篇的主要目的是加深对tarjan算法的理解,看tarjan主要是因为之前看朱刘算法要用,但是我一次都没有真正弄明白过tarjan…所以就花了好几天看"没用"的"小"论文(就结果来说,我想我一辈子都不会忘了tarjan是怎么回事了,虽然还是不能倒着写hhh

其实上述都是去年写的内容了,之前是放在我自己的博客上的,但是因为一些原因我需要先把博客关掉。但是我自己会时不时拿自己的博客进行复习,没了博客复习不便,所以就准备全部搬到csdn上,其实上个月中旬就打算开始搬结果拖到了现在…

之前是hexo+mathjax写的,公式写法是用自己写的脚本转过来的,有可能有没注意到或是没想到的地方,有错误的地方还请指出。

关于tarjan算法相关推荐

  1. tarjan算法不是很懂先mark一下。

     前面为转载的.后面是自己的理解. 三种tarjan算法(上) .这篇算是做一个总结吧. 求强连通分量 求无向图的割和桥 最近公共祖先 求强连通分量 基本概念:       强连通是有向图才有的概念. ...

  2. Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)...

    转载自:http://hi.baidu.com/lydrainbowcat/blog/item/2194090a96bbed2db1351de8.html 基本概念: 1.割点:若删掉某点后,原连通图 ...

  3. 0x66.图论 - Tarjan算法与无向图连通性

    目录 一.无向图的割点与桥 割点 桥/割边 时间戳 搜索树 追溯值 二.割边判定法则 三.割点判定法则 1.luogu P3388 [模板]割点(割顶) 2.luogu P3469 [POI2008] ...

  4. 『Tarjan算法 无向图的双联通分量』

    无向图的双连通分量 定义:若一张无向连通图不存在割点,则称它为"点双连通图".若一张无向连通图不存在割边,则称它为"边双连通图". 无向图图的极大点双连通子图被 ...

  5. Tarjan算法学习笔记

    一种由Robert Tarjan提出的求解有向图强连通分量的线性时间的算法. [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected ...

  6. 『追捕盗贼 Tarjan算法』

    追捕盗贼(COCI2007) Description 为了帮助警察抓住在逃的罪犯,你发明了一个新的计算机系统.警察控制的区域有N个城市,城市之间有E条双向边连接,城市编号为1到N. 警察经常想在罪犯从 ...

  7. 算法提高课-图论-有向图的强连通分量-AcWing 367. 学校网络:强连通分量、tarjan算法

    文章目录 题目解答 题目来源 题目解答 来源:acwing 分析: 第一问:通过tarjan算法求出强连通分量并且缩点后,统计入度为0的点的个数p即可. 第二问,至少加几条边才能使图变成强连通分量?这 ...

  8. CSP认证201509-4 高速公路[C++题解]:强连通分量、tarjan算法模板题

    题目分析 来源:acwing 分析: 所求即为强连通分量的个数,然后计算每个强连通分量中点的个数,相加即可. 所谓强连通分量,它是一个子图,其中任意两点可以相互到达,并且再加一个点,就不能满足任意两点 ...

  9. 算法提高课-图论-有向图的强连通分量-AcWing 1174. 受欢迎的牛:tarjan算法求强连通分量、tarjan算法板子、强连通图

    文章目录 题目解答 题目来源 题目解答 来源:acwing 分析: 强连通图:给定一张有向图.若对于图中任意两个结点x,y,既存在从x到y的路径,也存在从y到x的路径,则称该有向图是"强连通 ...

  10. Tarjan算法_LCA

    参考资料:Tarjan算法_LCA  tarjan算法求LCA  Tarjan 算法&模板 只是对其中的代码进行一下注释,如有错误还得回来再改. //不怕别人比你聪明,就怕别人比你聪明还比你努 ...

最新文章

  1. Alpha冲刺(9/10)
  2. Oracle创建自增id,sql直接创建
  3. ts快捷键 vscode_vscode怎么调试ts
  4. 雾霾经济:这10款产品,马云看了都想投资
  5. 使用闭包的方式实现一个累加函数 addNum
  6. 【HRBUST - 1621】迷宫问题II (bfs)
  7. win7虚拟机手机版_UTM 2.0 虚拟机来了,解决上网和无声音问题
  8. 使用U盘引导安装linux
  9. 思科模拟器服务器怎么显示字样,思科模拟器服务器怎么设置网关
  10. 医学案例统计分析与SAS应用--自学笔记
  11. Lonlife 1016 Change of Life
  12. 山西大学生计算机设计大赛,2017中国大学生计算机设计大赛山西赛区决赛在中北大学成功举办...
  13. 2013年EI收录的中国期刊
  14. ASR 混合高斯模型GMM的理解
  15. PTA L2-003 月饼
  16. 【福尔摩斯的约会】-PAT
  17. ES6新特性(部分语法)
  18. 微信小程序与后台交互案例
  19. layui表格 列自动适应大小失效
  20. 大数据学习系列:Hadoop3.0苦命学习(五)

热门文章

  1. 内向的人适合学计算机么,内向 反应也慢的人适合学车吗?
  2. 全球与中国液体壁纸行业需求趋势及投资策略分析报告2022-2028年
  3. 清华大学保研计算机推荐信模板,清华大学保研专家推荐信范文
  4. 复旦大学大三学生郭泽宇攻克世界难题
  5. 大话西游2智能自动五环 源码 有需要拿去图片自己做
  6. (OK) 华为全网通 honor 5x - KIW-AL10 安装 自己编译的 LineageOS 14.1 - 成功
  7. “雷曼事件”雷到我了?
  8. 【tkinter扩展库】tkdev4
  9. 如何看待无人驾驶技术产生的伦理道德问题
  10. Map集合和List集合总结