Floyd

这个算法核心的一句话:

  D^(0)[v][w]=min{D^(-1)[v][w],D^(-1)[v][0]+D^[v][0]+D^(-1)[0][w]}

        首先我们针对妄图准备两个矩阵D^(-1)和P^(-1),D^(-1)就是网图的邻接矩阵,P^(-1)初设为P[i][j]=j这样的矩阵,它主要用来存储路径。先给出网图的数值,和前面我写的Dijkstra中的数据是一样的https://www.cnblogs.com/Rysort/articles/9490547.html。

 

v0-v1 1   v0-v2 5  v1-v3 7  v1-v4 5  v1-v2 3  v2-v4 1  

v2-v5 7  v3-v6 3  v3-v4 2  v4-v6 6  v4-v7 9  v4-v5 3  

v5-v7 5  v6-v8 7  v6-v7 2  v7-v8 4

        代码如下,注意因为是求所有顶点到所有顶点的最短路径,因此,Pathmatirx和ShortPathTable都是二维数组。

typedef int Pathmatirx[MAXVEX][MAXVEX];
typedef int ShortPathTable[MAXVEX][MAXVEX];
//Floyd算法,求网图G中各顶点v到其余顶点w最短路径p[v][w]及带权长度D[v][w]
 1 void ShortestPath_Floyd(MGraph G,Pathmatirx *P,ShortPathTable *D)
 2 {
 3     int v,w,k;
 4     for(v=0;v<G.numVertexes;v++)//初始化D与F
 5     {
 6         for(w=0;w<G.numVertexes;w++)
 7         {
 8             (*D)[v][w]=G.matirx[v][w];//D[v][w]值即为对应点间的权值
 9             (*P)[v][w]=w;//初始化P
10         }
11     }
12     for(k=0;k<G.numVertexes;k++)
13     {
14         for(v=0;v<G.numVertexes;v++)
15         {
16             for(w=0;w<G.numVertexes;w++)
17             {
18                 if((*D)[v][w]>(*D)[v][k]+(*D)[k][w])
19                 {//如果经过下标为k顶点路径比原来两点间路径更短,将当前两点间权值设为更小的一个
20                     (*D)[v][w]=(*D)[v][k]+(*D)[k][w];
21                     (*P)[v][w]=(*P)[v][k];//路径设置经过下标为k的顶点
22                 }
23             }
24         }
25     }
26 }
  1. 程序开始运行,第4~11行就是初始化了D和P,使得它们称为D、P两个矩阵。从矩阵也得到,V0->V1路径权值是1,V0->V2路径权值是5,V0->V3无边连线,所以路径权值为最大值65535。
  2. 第12~25行,是算法的主循环,一共三层嵌套,k代表的就是中转顶点的下标。V代表起始顶点,w代表结束顶点。
  3. 当K=0时,也就是所有的顶点都经过V0中转,计算是否有最短路径的变化。可惜结果是,没有任何变化。
  4. 当K=1时,也就是所有的顶点都经过V1中转。此时,当V=0时,原本D[0][2]=5,现在由于D[0][1]+D[1][2]=4。因此有代码的第20行,二者取其最小值,得到D[0][2]=4,同理可得D[0][3]=8,D[0][4]=6,当V=2、3、4时,也修改了一些数据。由于这些最小权值的修改,所以在路径矩阵P上,也要作处理,将他们都改为当前的P[V][K]值。
  5. 接下来就是k=2一直到8结束,表示针对每个顶点做中转得到的计算结果,当然,我们也要清楚,D^(0)是以D^(-1)为基础,D^1是以D^0为基础,……,D^8是以D^7为基础,它们是有联系的,路径矩阵P也是如此。

        至此,最短路径就算是完成了,你可以看到矩阵第V0行的数值与迪杰斯特拉(Dijkstra)算法求得的D数组的数值是完全相同,都是{0,1,4,7,5,8,10,12,16}。而且这里是所有顶点的最短路径权值和都可以计算出。

        那么如何由P这个路径数组得出具体的最短路径呢?以V0到V8为例,P[0][8]=1,得到要经过顶点V1,然后将1取代0得到P[1][8]=2,说明要经过V2,然后将2取代1得到P[2][8]=4,说明要经过V4,然后将4取代2得到P[4][8]=3,说明要经过V3,……,这样很容易就推导出最终的最短路径为V0->V1->V2->V4->V3->V6->V7->V8。

        求最短路径的显示代码可以这样写。

 

for(v=0;v<G.numVertexes;v++)
{
    fow(w=v+1;w<G.numVertexes;w++)
    {
        printf("v%d-v%d wight: %d ",v,w,D[v][w]);
        k=P[v][w];//获得第一个路径顶点下标
        printf(" path: %d",v);//打印源点
        while(k!=w)//如果路径顶点下标不是终点
        {
            printf(" -> %d",k);//打印路径顶点
            k=P[k][w];//获得下一个路径顶点下标
        }
        printf(" -> %d\n",w);//打印终点
    }
    printf("\n");
}

 

        再次回过头来看看弗洛伊德(Floyd)算法,它就是一个二重循环初始化加一个三重循环权值修正,就完成了所有顶点到所有顶点的最短路径计算。因此是O(n^3)时间复杂度。如果你面临需求所有顶点至所有顶点的最短路径问题时,弗洛伊德(Floyd)算法应该是不错的选择。

        对求最短路径的两个算法(Dijkstra和Floyd)距离都是无向图,但它们对有向图依然有效,因为二者的差异仅仅是邻接矩阵是否对称而已。

 

posted @ 2018-08-18 12:26  子诚-  阅读(556)  评论(0编辑  收藏  举报