?数据结构-图之强连通

数据结构-图之强连通

在一个无向图G中,若从顶点v_i到顶点v_j有路径相连(当然从v_j到v_i也一定有路径),则称v_i和v_j是连通的。如果G是有向图,那么连接v_i和v_j的路径中所有的边都必须同向。如果图中任意两点都是连通的,那么图被称作连通图。图的连通性是图的基本性质。

连通分量:无向图G的一个极大连通子图称为G的一个连通分量(或连通分支)。连通图只有一个连通分量,即其自身;非连通的无向图有多个连通分量。

初级通路:通路中所有的顶点互不相同。初级通路必为简单通路,但反之不真。

强连通图:有向图G= (V,E)中,若对于V中任意两个不同的顶点x和y,都存在从x到y以及从y到x的路径,则称G是强连通图(Strongly Connected Graph)。相应地有强连通分量(Strongly Connected Component)的概念。强连通图只有一个强连通分量,即是其自身;非强连通的有向图有多个强连通分量。

强连通图指每一个顶点皆可以经由该图上的边抵达其他的每一个点的有向图。意即对于此图上每一个点对(Va,Vb),皆存在路径Va→Vb以及Vb→Va。强连通分量则是指一张有向图 G 的极大强连通子图 G‘。如果将每一个强连通分量缩成一个点,则原图 G 将会变成一张有向无环图。一张图被称为有向无环图当且仅当此图不具有点集合数量大于一的强连通分量,因为有向环即是一个强连通分量,而且任何的强连通分量皆具有至少一个有向环。

Kosaraju算法、Tarjan算法、Gabow算法皆为寻找有向图强连通分量的有效算法。但是由于在Tarjan 算法和 Gabow 算法的过程中,只需要进行一次的深度优先搜索,因而相对 Kosaraju 算法较有效率。

寻找强连通分量的算法,也可以用来解 2-SAT(2-satisfiability) 问题。Aspvall, Plass & Tarjan (1979)

根据 Robbins理论,当一个无向图为双连接图时,也会形成强连通(strong connectivity)。

缩点

由于强连通分量的特殊性,在一些实际应用中,会将每个强连通分量看成一个点,然后进行处理。这样做主要是为了降低图的复杂度,特别是在强连通分量规模大、数量多的情况中,利用“缩点”能大幅度降低图的复杂度。缩点后得到的图,必定是DAG。

将一个大图分解成多个连通分量,某些有向图算法可以分别在各个连通分量上独立运行,最后再根据分量之间的关系将所有的解组合起来。

(青玉案 元夕 [辛弃疾]

东风夜放花千树,更吹落星如雨。宝马雕车香满路,凤箫声动,玉壶光转,一夜鱼龙舞。

蛾儿雪柳黄金缕,笑语盈盈暗香去。众里寻他千百度,蓦然回首,那人却在,灯火阑珊处。)

Kosaraju算法(1978)

Kosaraju的算法(也称为Kosaraju-Sharir算法)是线性时间的算法来找到一个有向图的强连通分量。Aho, Hopcroft 和Ullman相信这个算法是由S. Rao Kosaraju在1978在一个未发表的论文上提出的。相同的算法还从Micha Sharir 1981年自己出版的书上被单独的发现,这个算法利用了一个事实,即转置图(同图中的每边的方向相反)具有和原图完全一样的强连通分量。

转置图,既逆图,是新创建的图,其每条边都与原图边的方向相反。

Kosaraju算法为了找到强连通分量,首先对图G运行DFS,计算出各顶点完成搜索的时间f;然后计算图的逆图GT,对逆图GT也进行DFS搜索,但是这里搜索时顶点的访问次序不是按照顶点标号的大小,而是按照各顶点f值由大到小的顺序;逆图DFS所得到的森林即对应连通区域。

上面我们提及原图G的逆图GT,其定义为GT=(V,ET),ET={(u,v):(v,u)∈E}}。也就是说GT是由G中的边反向所组成的,通常也称之为图G的转置。在这里值得一提的是,逆图GT和原图G有着完全相同的连通分支,也就说,如果顶点s和t在G中是互达的,当且仅当s和t在GT中也是互达的。

伪代码

1、对原图G进行深度优先遍历,记录每个节点的离开时间num[i]。

2、求得原图的逆图GT。

3、选择具有最晚离开时间的顶点,对逆图GT进行遍历,删除能够遍历到的顶点,这些顶点构成一个强连通分量。

4、如果还有顶点没有删除,继续步骤3,否则算法结束.

Kosaraju算法的流程简单,但是需要对图(和逆图)进行两次DFS搜索,而且读逆图的DFS搜索中顶点的访问顺序有特定的限制。

Tarjan算法

Tarjan算法 (以发现者Robert Tarjan命名)是一个在图中寻找强连通分量的算法。虽然发表时间更早,它仍可以被视为Kosaraju算法的一个改进。它的效率跟Gabow算法差不多。

此算法以一个有向图作为输入,并按照所在的强连通分量给出其顶点集的一个划分。图中的每个结点只在一个强连通分量中出现,即使是在有些结点单独构成一个强连通分量的情况下(比如图中出现了树形结构或孤立结点)。

Tarjan基于递归实现的深度优先搜索,在搜索过程中将顶点不断压入堆栈中,并在回溯时判断堆栈中顶点是否在同一联通分支。函数借助两个辅助数组pre和low,其中pre[u]为顶点u搜索的次序编号,low[u]为顶点u能回溯到的最早的顶点的次序编号。当pre[u]=low[u]时,则弹出栈中顶点并构成一个连通分支。Tarjan算法可以在线性时间内找出一个有向图的强分量,并且对原图进行一次DFS即可。

具体如下:任选一结点开始进行深度优先搜索(若深度优先搜索结束后仍有未访问的结点,则再从中任选一点再次进行)。搜索过程中已访问的结点不再访问。搜索树的若干子树构成了图的强连通分量。

结点按照被访问的顺序存入栈中。从搜索树的子树返回至一个结点时,检查该结点是否是某一强连通分量的根结点(见下)并将其从栈中删除。如果某结点是强连通分量的根,则在它之前出栈且还不属于其他强连通分量的结点构成了该结点所在的强连通分量。

根结点的性质

算法的关键在于如何判定某结点是否是强连通分量的根。注意“强连通分量的根”这一说法仅针对此算法,事实上强连通分量是没有特定的“根”的。在这里根结点指深度优先搜索时强连通分量中首个被访问的结点。

为找到根结点,我们给每个结点v一个深度优先搜索标号v.index,表示它是第几个被访问的结点。此外,每个结点v还有一个值v.lowlink,表示从v出发经有向边可到达的所有结点中最小的index。显然v.lowlink总是不大于v.index,且当从v出发经有向边不能到达其他结点时,这两个值相等。v.lowlink在深度优先搜索的过程中求得,v是强连通分量的根当且仅当v.lowlink = v.index。

Gabow算法

Gabow算法是Tarjan算法的提升版本,该算法类似于Tarjan算法。算法维护了一个顶点栈,但是还是用了第二个栈来确定何时从第一个栈中弹出各个强分支中的顶点,它的功能类似于Tarjan算法中的数组low。从起始顶点w处开始进行DFS过程中,当一条回路显示这组顶点都属于同一个强连通分支时,就会弹出栈二中顶点,只留下回边的目的顶点,也即搜索的起点w。

当回溯到递归起始顶点w时,如果此时该顶点在栈二顶部,则说明该顶点是一个强联通分量的起始顶点,那么在该顶点之后搜索的顶点都属于同一个强连通分支。于是,从第一个栈中弹出这些点,形成一个强连通分支。

时间: 2024-10-01 18:10:49

?数据结构-图之强连通的相关文章

图之强连通、强连通图、强连通分量 Tarjan算法

强连通分量 简介 在阅读下列内容之前,请务必了解图论基础部分. 强连通的定义是:有向图 G 强连通是指,G 中任意两个结点连通. 强连通分量(Strongly Connected Components,SCC)的定义是:极大的强连通子图. 这里想要介绍的是如何来求强连通分量. Tarjan 算法 Robert E. Tarjan (1948~) 美国人. Tarjan 发明了很多算法结构.光 Tarjan 算法就有很多,比如求各种联通分量的 Tarjan 算法,求 LCA(Lowest Comm

JavaScript数据结构——图的实现

在计算机科学中,图是一种网络结构的抽象模型,它是一组由边连接的顶点组成.一个图G = (V, E)由以下元素组成: V:一组顶点 E:一组边,连接V中的顶点 下图表示了一个图的结构: 在介绍如何用JavaScript实现图之前,我们先介绍一些和图相关的术语. 如上图所示,由一条边连接在一起的顶点称为相邻顶点,A和B是相邻顶点,A和D是相邻顶点,A和C是相邻顶点......A和E是不相邻顶点.一个顶点的度是其相邻顶点的数量,A和其它三个顶点相连,所以A的度为3,E和其它两个顶点相连,所以E的度为2

数据结构-图之基本概念

在图中的数据元素称为顶点(Vertex).顶点之间的关系称为边(Edge).图G是由顶点的有穷集合V,以及边的集合E组成. 由有序对构成的图为有向图(Digraph).在有向图中,两个顶点之间的由弧(Arc)连接,起始点(Initial node)为弧尾(Tail),终止点(terminal node)为弧首(Head). 由无序对构成的图是无向图(Undigraph).无向图的一条边相当于有向图的中两条边,即如果无向图的顶点v1和v2之间有一条边,那么既有从v1连接到v2的边,也有从v2连接到

poj 3352 Road Construction【边双连通求最少加多少条边使图双连通&&缩点】

Road Construction Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 10141   Accepted: 5031 Description It's almost summer time, and that means that it's almost summer construction time! This year, the good people who are in charge of the r

C#与数据结构--图的遍历

C#与数据结构--图的遍历 8.2 图的存储结构 图 的存储结构除了要存储图中各个顶点的本身的信息外,同时还要存储顶点与顶点之间的所有关系(边的信息),因此,图的结构比较复杂,很难以数据元素在存储区 中的物理位置来表示元素之间的关系,但也正是由于其任意的特性,故物理表示方法很多.常用的图的存储结构有邻接矩阵.邻接表.十字链表和邻接多重表. 8.2.1  邻接矩阵表示法 对于一个具有n个顶点的图,可以使用n*n的矩阵(二维数组)来表示它们间的邻接关系.图8.10和图8.11中,矩阵A(i,j)=1

数据结构--图 的JAVA实现(上)

1,摘要: 本系列文章主要学习如何使用JAVA语言以邻接表的方式实现了数据结构---图(Graph),这是第一篇文章,学习如何用JAVA来表示图的顶点.从数据的表示方法来说,有二种表示图的方式:一种是邻接矩阵,其实是一个二维数组:一种是邻接表,其实是一个顶点表,每个顶点又拥有一个边列表.下图是图的邻接表表示. 从图中可以看出,图的实现需要能够表示顶点表,能够表示边表.邻接表指是的哪部分呢?每个顶点都有一个邻接表,一个指定顶点的邻接表中,起始顶点表示边的起点,其他顶点表示边的终点.这样,就可以用邻

数据结构-图

1.图的定义 图:是一种灵活的数据结构,一般作为一种模型用来定义对象之间的关系或者联系.对象由顶点表示,而对象之间的关系或关联则通过顶点之间的边来表示. 2.图的应用 图算法.统计网络跳数.拓扑排序.图着色.哈密顿圈问题.分团问题.可序列化冲突 3.图的代码实现 /*graph.h*/ #ifndef GRAPH_H #define GRAPH_H #include <stdlib.h> #include "list.h" #include "set.h"

数据结构--图 的JAVA实现(下)

在上一篇文章中记录了如何实现图的邻接表.本文借助上一篇文章实现的邻接表来表示一个有向无环图. 1,概述 图的实现与邻接表的实现最大的不同就是,图的实现需要定义一个数据结构来存储所有的顶点以及能够对图进行什么操作,而邻接表的实现重点关注的图中顶点的实现,即怎么定义JAVA类来表示顶点,以及能够对顶点进行什么操作. 为了存储图中所有的顶点,定义了一个Map<key, value>,实际实现为LinkedHashMap<T, VertexInterface<T>>,key 为

数据结构--图--图的数组存储表示,深度优先搜索遍历和广度优先搜索遍历

图有四种存储结构:数组,邻接表,十字链表,邻接多重表.下面以数组为存储结构来实现图的深度优先搜索遍历和广度优先搜索遍历.其中广度优先搜索遍历中有用到STL中的queue,注意头文件的包含.具体代码如下: //图的数组(邻接矩阵)存储表示和深度优先遍历 const int MAX_VERTEX_NUM=20; //最大顶点数 typedef enum {DG,DN,UDG,UDN} GraphKind ;//(有向图,有向网,无向图,无向网) typedef int VRType; typedef