码迷,mamicode.com
首页 > 其他好文 > 详细

强连通分量

时间:2015-07-16 16:44:18      阅读:156      评论:0      收藏:0      [点我收藏+]

标签:

有向图的强连通分量

在有向图中,u可达v不一定意味v可达到u,相互可达的节点则属于同一个强连通分量。

某节点的传递闭包为该节点所处的强连通分量和它所有后代所处的强连通分量的节点。

若有向图的所有节点同属于一个强连通分量,则称该有向图为强连通图。

在有向图中,若某子图中的任一对节点都互为可达,则该子图称为有向图的强连通分量。

计算有向图中强连通分量的方法如下:将有向图G中每条边的方向取反,得到图G的一个转置GT,G和GT中的强连通分量相同。将每个强连通分量缩成一个节点,就可以得到一个无环有向图Gscc。

                                      

技术分享



   技术分享



    技术分享                                                                  

1、Procedure Kosaraju(G);
{调用dfs(G)计算出每个节点的f[u];
计算图G的转置GT;
调用dfs(GT),在主循环中按照f[u]递减的顺序依次对每个未访问点执行dfs过程,则得到的每棵dfs树恰好对应于一个强连通分量;
}


技术分享



技术分享


                           

V

0

1

2

3

4

5

6

7

8

9

10

11

12

d

1

17

2

3

4

5

7

8

9

19

21

23

20

f

16

18

15

14

13

6

12

11

10

26

22

24

25


技术分享



技术分享



f

26

25

24

22

18

16

15

14

13

12

11

10

6

v

9

12

11

10

1

0

2

3

4

6

7

8

5

0

0

0

0

1

2

2

2

2

2

3

3

2



模板:
const maxn=100;
var        //map[x,i] 记录与点x邻接的第i个点的编号   map[x,0]记录和x邻接的点的个数
  map,map1:array[1..maxn,0..maxn]of integer;  
  visit:array[1..maxn]of boolean;   //记录该点是否被遍历过
  list:array[1..maxn]of integer;      //记录n个点的遍历次序
  n,m,pos,scc:integer;                  //pos记录进入list数组的点的个数  scc记录强连通分量的个数 

procedure init;
var i,x,y:integer;
begin
  readln(n,m);
  for i:=1 to m do
  begin
    readln(x,y);
    inc(map[x,0]);
    map[x,map[x,0]]:=y;   
    inc(map1[y,0]);
    map1[y,map1[y,0]]:=x; 
end;
end;

procedure dfs(p:integer);
var i,j,k:integer;
begin
  visit[p]:=true; k:=map[p,0];
  for i:=1 to k do
  begin
    j:=map[p,i];
    if not visit[j] then dfs(j);
  end;
  inc(pos);  list[pos]:=p;
end;

procedure dfs1(p:integer);
var i,j,k:integer;
begin
  visit[p]:=true;
  k:=map1[p,0];
  for i:=1 to k do
  begin
    j:=map1[p,i];
    if not visit[j] then dfs1(j);
  end;
end;

procedure kosaraju;
var i,j,k:integer;
begin
fillchar(visit,sizeof(visit),false);
  for i:=1 to n do if not visit[i] then dfs(i); 
  fillchar(visit,sizeof(visit),false);  scc:=0;
  for i:=pos downto 1 do  //每深搜完一次,表示找完一个强连通图,增加scc
    if not visit[list[i]] then begin dfs1(list[i]); inc(scc); end;
end;

begin
  init;
  pos:=0;
  kosaraju;
  writeln(scc);
end.


2、Tarjan算法

Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。

技术分享


技术分享

算法流程演示:

1.从节点1开始DFS,把遍历到的节点加入栈中。搜索到节点u=6时,DFN[6]=LOW[6],找到了一个强连通分量。退栈到u=v为止,{6}为一个强连通分量。

技术分享

2.返回节点5,发现DFN[5]=LOW[5],退栈后{5}为一个强连通分量。

技术分享

3.返回节点3,继续搜索到节点4,把4加入堆栈。发现节点4向节点1有后向边,节点1还在栈中,所以LOW[4]=1。节点6已经出栈,(4,6)是横叉边,返回3,(3,4)为树枝边,所以LOW[3]=LOW[4]=1。

技术分享

4.继续回到节点1,最后访问节点2。访问边(2,4),4还在栈中,所以LOW[2]=DFN[4]=5。返回1后,发现DFN[1]=LOW[1],把栈中节点全部取出,组成一个连通分量{1,3,4,2}。

技术分享

至此,算法结束。经过该算法,求出了图中全部的三个强连通分量{1,3,4,2},{5},{6}。
可以发现,运行Tarjan算法的过程中,每个顶点都被访问了一次,且只进出了一次堆栈,每条边也只被访问了一次,所以该算法的时间复杂度为O(N+M)。

模板:

var
  a:array [1..1000,1..1000] of longint;
  low,dfn,c:array [1..1000] of longint;
  v,f,ff:array [1..1000] of boolean;
  i,j,m,n,x,y,d,ans:longint;


function min(x,y:longint):longint;
begin
  if x>y then
  exit(y);
  exit(x);
end;


procedure tarjan(x:longint);
var
  i:longint;
begin
  inc(d);
  low[x]:=d;
  dfn[x]:=d;
  f[x]:=true;
  for i:=1 to c[x] do
  begin
    if not v[a[x,i]] then
    begin
      v[a[x,i]]:=true;
      tarjan(a[x,i]);
      low[x]:=min(low[x],low[a[x,i]]);
    end else
    begin
      if f[a[x,i]] then
      low[x]:=min(low[x],dfn[a[x,i]]);
    end;
  end;
  if dfn[x]=low[x] then
  inc(ans);
end;


begin
  readln(n);
  for i:=1 to n do
  begin
    read(x);
    while x<>0 do
    begin
      inc(c[i]);
      a[i,c[i]]:=x;
      read(x);
    end;
  end;
  for i:=1 to n do
  if not v[i] then
  begin
    v[i]:=true;
    tarjan(i);
  end;
  writeln(ans);
end.


有几道习题:

1.http://blog.csdn.net/boyxiejunboy/article/details/46891399

2.http://blog.csdn.net/boyxiejunboy/article/details/46891417

3.http://blog.csdn.net/boyxiejunboy/article/details/46891815

版权声明:本文为博主原创文章,未经博主允许不得转载。

强连通分量

标签:

原文地址:http://blog.csdn.net/boyxiejunboy/article/details/46912203

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!