zoukankan      html  css  js  c++  java
  • 极大强连通分量的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.
  • 相关阅读:
    java 数组及数组得内存管理总结
    js 日期格式化
    url获取参数值,支持中文、英文
    C# log4net 的日志代码配置
    js 处理浏览器显示地址
    mui <a>标签跳转失效的处理
    js 实时输入事件
    asp.mvc 页面获取当前请求的控制器和方法
    js 获取元素值
    DllImport System.DllNotFoundException 找不到指定的模块。 (Exception from HRESULT: 0x8007007E)
  • 原文地址:https://www.cnblogs.com/neverforget/p/2209611.html
Copyright © 2011-2022 走看看