《数据结构与算法分析 C++描述》之图论算法理解1

 

深度优先搜索的应用包括三部分:割点(无向图),欧拉回路(无向图),强分支(有向图)。

首先,理解所谓深度优先搜索。即前序遍历的一种形式。其特点是每次搜索的深度优先生成树必然是图的一个连通分量,总沿着路径一直触及到最深处才逐步返回。深度优先搜索形成森林的原因:(1)不连通的无向图(2)非强连通的有向图。对无向图,很确定地有几个连通域就有几棵树;对有向图,左树(先生成的树)的所有元素都不会指向右边树的任何元素,否则,生成树时一定能够遍历过去。而一棵树内部又可能有好几个双连通域,采用后序遍历编号后,只能说在树内部,大编号的顶点一定能到达小编号的顶点。

无向图的割点。一个割点将图分为两部分,两部分之间的顶点必须通过该割点才能连接上。若从A部分为起点深度优先遍历,则B部分的所有顶点编号必然在割点之后。而A的顶点可以分为两部分,编号比割点小的A_Small(在进入割点之前遍历)和编号比割点大(在出了割点之后遍历)的A_Big。下面考虑两种双连通的可能性:(1)假如B的顶点反向边触及到了A_Small,那么其Low值将会比割点小;(2)假如B的顶点正向边触及到了A_Big,那么遍历B时能直接遍历到A_Big,A_Big就不可能是A_Big,而是B,这种情况不存在。综上,B部分要想不被割点阻隔,只能利用一条反向边直达割点之前的某一点,及反向边儿子的Num小于割点的Num,仅此一条出路。那么,Low的定义如下:

    Low(v) = Min( Num(v) , 树儿子中最小Low(w), 反向边儿子中最小Num(w) )

也就是说,顶点v能够触及到的最小顶点编号Low(v)要么是自己反向边触到的顶点号Num(w)(必然比自己Num(v)小),要么是自己儿子能触及到的最小顶点号(我能触到我儿子,所以儿子能触到的就是老子能触到的),实在不行就只能认命选自己的编号Num(v)。到现在就可以定义割点的条件了:如果某一个顶点v竭其所能能够触及到的最小顶点编号Low(v)都没有到达其父顶点之前的某一个顶点,那么只能接受被父亲隔离的现实。所以结论是:某一顶点如果存在一个儿子的Low(w)>=Num(v),那么这个顶点就是一个割点,它隔离这个儿子;某一顶点如果所有儿子都满足Low(w)< Num(v),那么说明它所有儿子都触及到了老子前面的顶点,一个儿子也没隔离住,这就不是一个割点。

无向图的欧拉回路。这个比较简单,前提是每个顶点连接的边数必须为偶。那么从起点深度优先遍历吧,无向图是连通的,必然能回到源点。如:a,b,d,e,d,a。那么再。从b开始深度优先遍历(如果a已经没有连接的边了),得b,w,o,b,合并a,b,w,o,b,d,e,d,a。下一个考察w,以此直到不再存在边。自我感觉,欧拉回路用到的深度优先遍历唯一地方是:利用深度优先搜索一条回到自己的路径。

有向图的强分支。即寻找哪些点集是彼此之间是强连通的。依据是,如果a->b->c,并且a<-b-<c那么a,b,c就是一个强连通域。方法是依据的简单实现:两次建立深度优先生成森林。(1)建立深度优先生成森林。根据深度优先搜索性质,左树不会指向右树,因而强分支在每棵树的内部。(2)根据第一棵树,进行后序遍历编码。之所以后序编码,是为了保证根永远比叶子大,即在a->b->c中a>b>c,服务于第三步。(3)建立第二个深度优先生成森林。将原图G所有有向边反向得图Gr,利用(2)中的编码大小,从大到小的顺序开始深度优先遍历,这样做的效果是:新遍历中,在森林1的顶点,右树先于左树(G中左树不会指向右树,因而Gr中右树不会指向左树,树与树彼此保持独立);原树内部中,依然按照原树的顶点顺序开始搜索,只不过边都反向了。如果第二次还能组成树的顶点之间就满足了a->b->c,并且a<-b-<c的条件,即,强连通分支。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值