图遍历算法应用--有向图的顶点可达性(无向图的连通性)(2)

     顶点v到w可达就是指从v到w至少有一条路径。那么在有向图中要判断v到w是否可达,我们只需要以v为起点遍历一遍图,看能否遍历到w即可。当然在遍历时可以自己适当的加一些限制条件,提高算法效率,如:不需要遍历完所有顶点,只要遍历到w就可以结束遍历。所以时间为<=O(N2);

     推广1:判断顶点v到其他所有顶点的可达性,以顶点v为起点,遍历整个图,能被遍历到的顶点就是从v可达的,否则就是不可达,时间为o(n2) 。对于无向图,如果完成整个遍历后还有顶点没有被访问,那么这个图就是不连通。

    推广2:判断任意两点之间是否可达,当然我们可以以每个顶点为起点,然后按推广2的方法去多次遍历图,这样的时间复杂度为o(n3),而且在遍历的过程中可以适当的改进(可以自己实现)。

在此我们学习一种完全不同的方法—-Warshall算法,来实现这个任务:(有关Warshall算法的描述部分转载:http://www.cnblogs.com/brokencode/archive/2011/07/01/2095158.html

Warshall算法通过动态规划的形式,以多阶段决策的方式来逐步构建一个有向图的传递闭包:

 1)有向图的邻接矩阵表示了一个有向图,实际上有向图的邻接矩阵我们可以看作是没有经过任何中间顶点即一个点仅到它的邻接点为可达)的图的传递闭包(传递闭包的初始条件)

2)我们可以通过一次加入一个点的方式(一共n次,加入n个点,n步决策)来构造最终的传递闭包:

—-用R0表示邻接矩阵,以后每次加入一个顶点来构造R1,R2…….Rn。

—如果 r(i , j) 在Rk-1中为1,那么加入顶点k作为中间节点后,r(i , j) 在Rk中的值仍为1(如果可达了,加入点之后肯定还是可达)

–如果r(i , j)在Rk-1中不为1,仅当 r(i , k) = 1 且 r(k , j) = 1,r(i , j)在Rk中才为1(如果现在不可达,仅当加入的一个中间节点可以作为一个桥梁使之可达,才可达)

即下面2条规则:

《图遍历算法应用--有向图的顶点可达性(无向图的连通性)(2)》

如果不想分2种情况,用与或式可以直接写成下式:

《图遍历算法应用--有向图的顶点可达性(无向图的连通性)(2)》

括号在”或“后面。伪代码见下面:

《图遍历算法应用--有向图的顶点可达性(无向图的连通性)(2)》

 

Warshall算法的实现:

void Warshall(int G[][Max])

{

for(int k=0;k<Max;k++){

       for(inti=0;i<Max;i++){

            for(intj=0;j<Max;j++)

                  G[i][j]=G[i][j]||(G[i][k]&&G[k][j]);

       }

}

}

Warshall算法分析:

由上面的介绍我们可以得知:Gk[i][j]=Gk-1[i][j]||(Gk-1 [i][k]&&G k-1 [k][j]),然而我们在算法实现时仅仅为:G[i][j]=G[i][j]||(G [i][k]&&G [k][j])这样对吗?答案是肯定的,现在我们来分析下why?

对最外层的K循环,在每次确定k后,循环i和j,G[i][k]位于A段或c段,同理G[j][k]位于B段或d段 (如下图)

《图遍历算法应用--有向图的顶点可达性(无向图的连通性)(2)》

     对于每一对i,j将G中元素分为两部分了:一部分已经是Gk中元素了,即已经完成了赋值,而另一部分还是Gk-1这部分元素还没来的急赋值(如上图)。

     那么对于Gk[i][j]=Gk-1[i][j]||(Gk-1 [i][k]&&G k-1 [k][j]),左边的Gk[i][j]是赋值后的位置i,j的值,就是G[i][j]赋值后;左边的Gk-1[i][j]是赋值前的位置i,j的值就是G[i][j]。

     现在我们来考虑G k-1 [i][k],如果G k-1 [i][k]位于图中的c断,那么G [i][k]还没有赋新值,那么G[i][k]就是G k-1 [i][k]了。而如果G k-1 [i][k]位于A段,此时的G[i][k]已经完成赋值,已经是G k [i][k]了。但我们继续分析:

G k [i][k]=Gk-1[i][k]||( Gk-1[i][k]&&Gk-1[k][k]),所以G k [i][k]= G k-1 [i][k],所以说的G[i][k]== G k [i][k]==G k-1[i][k]。

     同理对于G k-1 [k][j],如果G k-1 [k][j]位于图中B断,那么G [k][j]还没有赋新值那么G[k][j]就是G k-1 [k][j]了,如果G k-1[k][j]位于图中d断,此时G[k][j] 已经完成赋值,已经是G k [k][j]了。但G k [k][j]=Gk-1[k][j]||(Gk-1[k][k]&& Gk-1[k][j]),所以G[k][j]== G k [k][j]==G k-1 [k][j]

所以对于Gk[i][j]=Gk-1[i][j]||(Gk-1 [i][k]&&G k-1 [k][j])我们就可以直接在一个矩阵内部操作了,改为G[i][j]=G[i][j]||(G [i][k]&&G [k][j]),这样就少了矩阵间赋值,且省空间。

 

 

 

    原文作者:数据结构之图
    原文地址: https://blog.csdn.net/z568954956/article/details/6712037
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞