上一篇关于Dijkstra算法的实现发现一个问题,就是Dijkstra算法主要针对的是一个顶点到其他顶点间的最小距离,那么问题来了,如何实现每一对顶点间的最小距离,是选择Dijkstra算法进行n次遍历?显然发现会很麻烦,对于n次遍历的Dijkstra算法,时间复杂度为O(n^3)。这里介绍的Floyd算法时间复杂度算然和前者相同,但是至少实现的形式上能简单一些!
Floyd算法基本思想是:
假设求从顶点vi到vj的最短路径。如果从vi到vj有弧,则从vi到vj存在一条长度为arc[i][j]的路径,该路径不一定是最短路径,尚需进行n次试探。首先考虑路径(vi,vj)和(vi,v0,vj)是否存在(即判别弧(vi,v0)和(v0,vj)是否存在)。如果存在,则比较(vi,vj)和(vi,v0,vj)的路径长度取长度较短者为从vi到vj的中间顶点的序号不大于0的最短路径。假设在路径上在增加一个顶点v1,也就是说,如果(vi,...,v1)和(v1,.....,vj)分别是当前找到的中间顶点的序号不大于0的最短路径,那么(vi,...,v1,...vj)就用可能是从vi到vj的中间点点序号不大于1的最短路径。讲他和已经得到的从vi到vj中间顶点序号不大于0的最短路径比较,从中选出中间顶点的序号不大于1 的最短路径之后在增加一个顶点v2,继续进行试探。此时我们需要借助三阶矩阵来实现这个过程的存储。
下面把算法伪代码贴出来:
给出书中的测试用例图:
还有建立的辅助矩阵:
下面分享代码:
/*
************************************************
*Name : Matrix_Floyd.c *
*Date : 2015-06-17 *
*Author : sniper *
*Aim : Floyd algrithm to get the shortest route*
* each node to others in the graph *
************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_MATRIX_NUMBER 100
#define INF 32768
int main()
{
int i,j,k,l;
int node_count,edge_count;
int node_pair1,node_pair2,weight;
int Distance[MAX_MATRIX_NUMBER][MAX_MATRIX_NUMBER];
int edge[MAX_MATRIX_NUMBER][MAX_MATRIX_NUMBER];
int Path[MAX_MATRIX_NUMBER][MAX_MATRIX_NUMBER];
node_count=edge_count=node_pair1=node_pair2=weight=0;
printf("please input the number of node and edge: ");
scanf("%d %d",&node_count,&edge_count);
memset(Distance,0,sizeof(Distance));
memset(edge,0,sizeof(edge));
memset(Path,0,sizeof(Path));
/*
*Create the graph
*/
for(i=0;i<edge_count;i++)
{
printf("please input the node pair: ");
/*
*node_pair1 node_pair2 two side of edge and
*the weight means the weight of edge
*/
scanf("%d %d %d",&node_pair1,&node_pair2,&weight);
edge[node_pair1][node_pair2] = weight;
}
printf("after create the graph is :\n");
for(i=0;i<node_count;i++)
{
for(j=0;j<node_count;j++)
{
if(i!=j && edge[i][j]==0)
edge[i][j]=INF;
printf(" %d ",edge[i][j]);
}
printf("\n");
}
/*
*Floyd
*/
for(i=0;i<node_count;i++)
{
for(j=0;j<node_count;j++)
{
Distance[i][j]=edge[i][j];
printf(" %d ",Distance[i][j]);
for(k=0;k<node_count;k++)
if(Distance[i][j]>0)
{
(Path+i)[j][i]=1;
(Path+i)[j][j]=1;
}
}
printf("\n");
}
printf("+++++++++++++++++++++++++++++++++\n");
for(i=0;i<node_count;i++)
for(j=0;j<node_count;j++)
for(k=0;k<node_count;k++)
if(Distance[j][i]+Distance[i][k]<Distance[j][k])
{
Distance[j][k]=Distance[j][i]+Distance[i][k];
for(l=0;l<node_count;l++)
(Path+j)[k][l] = (Path+j)[i][l]||(Path+i)[k][l];
}
for(i=0;i<node_count;i++)
{
for(j=0;j<node_count;j++)
{
if(Distance [i][j]!=0)
{
printf("%c -> %c = %d \n",i+'A',j+'A',Distance[i][j]);
}
}
}
return 0;
}
当然了还有测试用例:
3 5
0 1 4
0 2 11
1 0 6
1 2 2
2 0 3
运行结果如下图:
https://github.com/cremyos/Graph_Floyd/
这个代码无法打印详细的路径,因为在84行处的
(Path+j)[k][l] = (Path+j)[i][l]||(Path+i)[k][l];
应该是把路径拼接起来,结果采用的是或运算,所以出问题了,具体怎么改。。。还没想到什么好的办法!