Tarjan算法 Pascal语言描述

合集下载
相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Tarjan算法Pascal语言描述
Tarjan算法Pascal语言描述
TonyShaw
那天做了个2-sat题,里面牵扯到求有向图的强连通分量,我这么弱,显然不会,于是从网上找求有向图的强连通分量的方法,有一个是DFS两遍,同时建原图与补图,算法名字是B???忘掉了,反正当时同时看见了Tarjan算法。

鉴于我对于Tarjan的略微崇拜,于是想先学一下Tarjan。

写这篇文章的原因在于,我在网上没有找到Pascal语言描述的程序,同时一些关于这个算法的解释不是很清楚,所以我想写一下,算是我对该算法理解的总结,也算是为其他要学习该算法的人提供点无用的参照吧。

算法思想:从一个点开始,进行深度优先遍历,同时记录到达该点的时间(dfn记录到达i 点的时间),和该点能直接或间接到达的点中的最早的时间(low记录这个值,其中low的
初始值等于dfn)。

(如图。

假设我们从1开始DFS,那么到达1的时间为1,到达2的时间为2,到达3的时间为3。

同时,点1能直接或间接到达的点中,最小时间为1,点2能通过3间接到达点1,所以点2可到达最早的点时间为1,点3可以直接到达点1,故点3到达的最早的点的时间为1。

)。

对于每一个没有被遍历到的点A,如果从当前点有一条到未遍历点A的有向边,则遍历到A,同时将点A入栈,时间戳+1并用dfn[a]记录到达点A的时间,枚举从A发出的每一条边,如果该边指向的点没有被访问过,那么继续dfs,回溯后low[a]:=min(low[a],low[j])(其中j为A可以到达的点。

)如果该点已经访问过并且该点仍在栈里,那么low[a]=min(low[a],dfn[j])。

解释:若点j没有被访问过,那么回溯后low[j]就是j能到达最早点,a能到达的最早点当然就是a本身能到达的最早点,或者a通过j间接到达的最早点。

若点j已经被访问过,那么low[j]必然没有被回溯所更新。

所以low[a]就等于a目前能到达的最小点或a直接到达点j
时点j的访问时间。

注意:两个句子中的“或”其实指的是两者的最小值。

那么如果我们回溯
到一个点K他的low[k]=dfn[k]那么我们将K及其以前在栈中的点依次弹出,这些点即为一个强连通分量。

证明:因为该点dfn=low,所以在栈中的该点以上的点都能由该点直接或间接的到达。

同时栈中在该点前的任意一点j,其dfn[j]<>low[j](否则点j比点k靠前,又因为dfn[j]=low[j],j 一定先被弹出了。

)那么这个点j通过low[j]这个时间的点,一定能到达点k,(否则,low[j]能到达点i,又因为dfn>=low所以有2种情况1、dfn>low:那么我们可以找到前面一个更小的点。

2、dfn=low:应该在回溯到i的时候就找到了一个强连通分量,从而出栈了。

而点k前的点没有出栈,证明其中任意一点都能直接或者间接到达点k,进而证明这些点可以两两互达。

程序如下:
procedure Tarjan(i:longint);
var j:longint;
begin
inc(time); dfn:=time; low:=time;//初始化到达点i的时间。

push(i); left:=false; v:=true;//点i入栈,left表示点i里没离开栈,v表示点i有没有被访问过。

j:=head;//数组模拟邻接表
while j<>0 do
begin
if not left[e[j]] then low:=min(low,dfn[e[j]]);
if not v[e[j]] then begin Tarjan(e[j]); low:=min(low,low[e[j]]); end;
j:=next[j];
end;
j:=-1;
if dfn=low then//找到强连通分量,出栈。

begin
while j<>i do begin j:=pop; write(j,' '); left[j]:=true; end;
writeln;
end; end;。

相关文档
最新文档