求强连通分量的Kosaraju算法和Tarjan算法的比较 by ljq.docVIP

  • 33
  • 0
  • 约6.92千字
  • 约 15页
  • 2020-03-02 发布于四川
  • 举报

求强连通分量的Kosaraju算法和Tarjan算法的比较 by ljq.doc

求强连通分量的Kosaraju算法和Tarjan算法的比较 一、定义 在有向图中,如果两个顶点vi,vj间有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。如果有向图的每两个顶点都强连通,则称该有向图是一个强连通图。非强连通的有向图的极大强连通子图,称为强连通分量(strongly connected components)。 而对于一个无向图,讨论强连通没有意义,因为在无向图中连通就相当于强连通。 由一个强连通分量内的所有点所组成的集合称为缩点。在有向图中的所有缩点和所有缩点之间的边所组成的集合称为该有向图的缩图。 例子: 原图: 1 1 2 4 3 7 6 5 缩图: 1 1 4 3 2 上面的缩图中的 缩点1包含:1、2,; 缩点2包含:3; 缩点3包含:4; 缩点4包含:5、6、7。 二、求强连通分量的作用 把有向图中具有相同性质的点找出来,形成一个集合(缩点),建立缩图,能够方便地进行其它操作,而且时间效率会大大地提高,原先对多个点的操作可以简化为对它们所属的缩点的操作。 求强连通分量常常用于求拓扑排序之前,因为原图往往有环,无法进行拓扑排序,而求强连通分量后所建立的缩图则是有向无环图,方便进行拓扑排序。 三、Kosaraju算法 时间复杂度:O(M+N) 注:M代表边数,N代表顶点数。 所需的数据结构:原图、反向图(若在原图中存在vi到vj的有向边,在反向图中就变成为vj到vi的有向边)、标记数组(标记是否遍历过)、一个栈(或记录顶点离开时间的数组)。 算法描叙:   步骤1:对原图进行深度优先遍历,记录每个顶点的离开时间。   步骤2:选择具有最晚离开时间的顶点,对反向图进行深度优先遍历,并标记能够遍历到的顶点,这些顶点构成一个强连通分量。 步骤3:如果还有顶点没有遍历过,则继续进行步骤2,否则算法结束。 hdu1269(Kosaraju算法)代码: #includecstdio #includecstdlib const int M=10005; struct node { int vex; node *next; }; node *edge1[M],*edge2[M]; bool mark1[M],mark2[M]; int T[M],Tcnt,Bcnt; void DFS1(int x) { mark1[x]=true; node *i; for(i=edge1[x];i!=NULL;i=i-next) { if(!mark1[i-vex]) { DFS1(i-vex); } } T[Tcnt]=x; Tcnt++; } void DFS2(int x) { mark2[x]=true; node *i; for(i=edge2[x];i!=NULL;i=i-next) { if(!mark2[i-vex]) { DFS2(i-vex); } } } int main() { int n,m; while(scanf(%d%d,n,m)) { if(n==0m==0) { break; } int i,a,b; for(i=1;i=n;i++) { mark1[i]=mark2[i]=false; edge1[i]=NULL; edge2[i]=NULL; } node *t; while(m--) { scanf(%d%d,a,b); t=(node *)malloc(sizeof(node)); t-vex=b; t-next=edge1[a]; edge1[a]=t; t=(node *)malloc(sizeof(node)); t-vex=a; t-next=edge2[b]; edge2[b]=t; } Tcnt=0; for(i=1;i=n;i++) { if(!mark1[i]) { DFS1(i); } } Bcnt=0;//Bcnt用于记录强连通分量的个数 for(i=Tcnt-1;i=0;i--) { if(!mark2[T[i]]) { DFS2(T[i]); Bcnt++; } } if(Bcnt==1)//如果强连通分量的个数为1则说明该图是强连通图 {

文档评论(0)

1亿VIP精品文档

相关文档