极大强连通分量的Tarjan算法

                             求极大强连通分量的Tarjan算法

   首先,在有向图G中,如果两个顶点vi,vj间(vi<>vj)都有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components),如果一个强连通分量中不再能加入任何一个顶点,则这个强连通分量是一个极大强连通分量。

   由上面的定义,可以知道,强连通分量中各点可以互相到达,则我们可以找到每个极大强通分量的“根结点”,再通过从底层节点向上推的方法求出一个极大强连通分量,所以关键在于求出根结点,所以这里加入两个数组,dfn,和low,其中dfn为搜索序号,表示第几个搜到该点,而low表示该节点向上最远可以回到的节点,显然当一个节点的dfn[i]=low[i]时,它就是这一个极大强连通分量的根,之后搜索到的点包含在这个极大强连通分量中,下面就要考虑一下如何取出这个极大强连通分量,于是维护一个栈,每搜索一个节点,就把它压入栈中,那么当我们发现根结点时,在它后面入栈的都是它代表的极大强连通分量中的节点,只需要弹栈直到根结点出栈即可。

【程序伪代码】

   Dfs(k)

     Inc(time);    //搜索的序号变量

     Low[x]=time   //当前节点最远可以回到的点的时间戳

     Dfn[x]=time    //时间戳

     Push(x)   //入栈

     Instack[x]=true   //将x节点在栈中标记为真

     For i=x的所有儿子

       If 没有访问过 x   //还没有被搜索过

         Dfs(i)

         Low[x]=Min(low[x],low[i])

//搜索之后发现儿子节点能到达的最早时间戳比x要早,则更新 

       Else //已经搜索过

         If  (i在栈中)and(dfn[i]<low[x])

//在栈中说明属于同一个强连通分量,而如果时间戳更早,显然需要更新

           Low[x]=dfn[i]

      If dfn[x]=low[x] //如果该节点是一个强连通的根结点

        Inc(num) //强连通数增加

        While true do

          Pop //弹出该强连通的结点

          Instack[stack[top]]=false//在栈内标记为假

          If stack[top+1]=x//如果根结点已经输出

            Break //跳出

View Code
 1 program targan(input,output);
2 type
3 node = ^link;
4 link = record
5 goal : longint;
6 next : node;
7 end;
8 var
9 stack : array[1..1000] of longint;
10 l : array[1..1000] of node;
11 instack : array[1..1000] of boolean;
12 dfn : array[1..1000] of longint;
13 low : array[1..1000] of longint;
14 ans : array[1..1000] of longint;
15 num,e : longint;
16 m,n,top,cnt : longint;
17 procedure add(x,y: longint );
18 var
19 t : node;
20 begin
21 new(t);
22 t^.goal:=y;
23 t^.next:=l[x];
24 l[x]:=t;
25 end; { add }
26 procedure init;
27 var
28 i,x,y : longint;
29 begin
30 readln(n,m);
31 cnt:=0;
32 for i:=1 to n do
33 l[i]:=nil;
34 fillchar(instack,sizeof(instack),false);
35 for i:=1 to m do
36 begin
37 readln(x,y);
38 add(x,y);
39 end;
40 end; { init }
41 procedure dfs(x :longint );
42 var
43 t : node;
44 begin
45 inc(cnt);
46 dfn[x]:=cnt;
47 low[x]:=cnt;
48 inc(top);
49 stack[top]:=x;
50 instack[x]:=true;
51 new(t);
52 t:=l[x];
53 while t<>nil do
54 begin
55 if dfn[t^.goal]=0 then
56 begin
57 dfs(t^.goal);
58 if low[t^.goal]<low[x] then
59 low[x]:=low[t^.goal];
60 if dfn[t^.goal]<low[x] then
61 low[x]:=dfn[t^.goal];
62 end
63 else
64 if (instack[t^.goal]=true)and(dfn[t^.goal]<low[x]) then
65 begin
66 low[x]:=dfn[t^.goal];
67 end;
68 t:=t^.next;
69 end;
70 if low[x]=dfn[x] then
71 begin
72 inc(num);
73 while true do
74 begin
75 ans[stack[top]]:=num;
76 instack[stack[top]]:=false;
77 dec(top);
78 if stack[top+1]=x then
79 break;
80 end;
81 end;
82 end; { dfs }
83 procedure print;
84 var
85 i : longint;
86 begin
87 for i:=1 to n do
88 write(ans[i],'');
89 end; { print }
90 begin
91 init;
92 for e:=1 to n do
93 if dfn[e]=0 then
94 dfs(e);
95 print;
96 End.
原文地址:https://www.cnblogs.com/neverforget/p/2209611.html