- 1、本文档共8页,可阅读全部内容。
- 2、有哪些信誉好的足球投注网站(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
- 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
算法学习:有向图的强连通分量
DFSDFS就是深度 优先有哪些信誉好的足球投注网站,裸的DFS是很启蒙的一个东西,所以就不废话了,直接给出它的程序:procedure dfs(x:longint);?var j:longint;?begin? flag[x]:=1;? for j:=1 to n do?? if (a[x,j]=1)and(flag[j]=0) then??? dfs(j);?end;其中flag是是否遍历过的标 记,a是邻接矩阵。当然,在主程序中需要有这一句:for i:=1 to n do?if flag[i]=0 then dfs(i);而不是直接的dfs(1),因为节点1并不一定能到达所有节点。这是初学者(我?)常犯的一个错误。当然,DFS进行的顺 序并不一定是按节点编号顺序。一般按节点编号顺序DFS只是为了方便,有时我们必须以不同的顺序进行DFS(比如下面将要谈到的Kosaraju算法)。
时间戳与点的分类设 置全局变量time,初始值为0,当遇到一个事件点的时候就++1。时间点分为两种:发现某一节点和结束某一节点(即在DFS过程的开头和结尾)。发现节 点x时,发现时间戳d[x]=time;结束节点x时,结束时间戳f[x]=time。根据时间戳状态的不同可以将节点进行分类:白 点==没有时间戳的节点==未遍历的节点灰点==仅有发现时间戳的节点==正在遍历以此节点为根的子树的节点黑点==有发现时间戳和结束 时间戳的节点==完成的节点注意:点的分类随time增长而变化,且DFS结束后所有点都是黑点,所以用一个全局变量保存点的分类没有意义。 DFS过程中可以直接通过时间戳得知点的分类。
边的分类在 DFS过程中所有顶点和经过的边形成了一棵DFS树。根据图中的边在DFS树中的位置和发现此边时入节点的分类(这里说的是有向图,每条边有出节点和入节 点)将边分为四类:树枝==DFS树中的边==入节点为白点反向边==某一节点x到其DFS树中祖先y的边==入节点为灰点正向 边==某一节点x到其DFS树中后代y的边==入节点为黑点==d[x]d[y]横叉边==某一节点x到DFS树中另一子树上节点y的 边==入节点为黑点==d[x]d[y]如下图:若以节点序号顺序进行DFS,则形成下面一棵DFS树(粗边是树枝,其他类型的边在旁边有 说明)
横叉边在图中是只能向左的,通过DFS的过程可以知道这一点。这对我们设计算法很有帮助。注意,边的分类与点的分类完全不同。点的分类随着时间变化,而边的分类是不变的。所以我们需要用一个全 局变量保存边的分类。在后面的程序中,我们用kl[i,j]表示i到j的边的分类,树枝、反向边、正向边、横叉边分别用1/2/3/4表示。
强连通分量一个有向图中,如果节点i能够通过一些边到达节点j,就 简写成i能到达j。如果对于任意两个节点i,j均有i能到达j或j能到达i,则说此图是连通的。如果对于任意两个节点i,j均有i能到达j且j能到达i, 则说此图是强连通的。对于一个无向图,说强联通没有意义,因为此时强连通就是连通。而对于一个有向图,它不一定是强连通的,但可以分为几个极大的 强连通子图(“极大”的意思是再加入任何一个顶点就不满足强连通了)。这些子图叫做这个有向图的强连通分量。在上图中,强连通分量是 A{1},B{2,4},C{3,5,6,7}。在一个强连通分量中的节点由于有着相似的拓扑性质,所以我们可以将其紧缩为一个节点(这让我想到了什么?化 学里的“族”),于是就大大减小了图的规模。比如上图紧缩为A,B,C三个节点后,整个图就成为了B←A→C的简单形式。所以强连通分量是一个 很有意义的东西。然而如果根据定义,对每个节点进行一次O(n2)的DFS以求出它所能到达的顶点的话,整 个算法的时间复杂度就是迟钝的O(n3)。 下面将介绍两种用O(n2)求强连通分量的算 法:Kosaraju算法和Tarjan算法。
Kosaraju算法Kosaraju算法基于以下思想:强连通分量一定是某种DFS形成的DFS树森林。 Kosaraju算法给出了更具体的方式:任意进行一次DFS,记录下每个节点的结束时间戳f[i]。按f[i]的大小对节点进行排 序(从小到大)。以的排序结果进行一次DFS,所得的DFS树森林即为强连通分量。这次DFS可以用Floodfill进行,把每个强连通分量标上 不同序号。(这就是OI界传说中的“求强连两遍DFS的算法”)比如上图,我们可以得到:d[1]=1? f[1]=14d[2]=2? f[2]=5d[3]=6? f[3]=13d[4]=3? f[4]=4d[5]=7? f[5]=8d[6]=9? f[6]=12d[7]=10
文档评论(0)