一. 求所有顶点间的最短路径
方法一:每次以一个顶点为源点,重复执行迪杰斯特拉算法 n 次
方法二:使用弗洛伊德算法
两种方法的时间复杂度相同都为 n^3,但是弗洛伊德算法却更为简单
二. 弗洛伊德(Floyd)算法
1. 算法思想
- 逐个顶点试探
- 从 Vi 到 Vj 的所有可能存在的路径
- 选出一条长度最短的路径
步骤:
- 初始时设置一个 n 阶方阵,令其对角线元素为 0,若存在弧<Vi,Vi>,则对应元素为权值;否则为∞。
- 逐步试着在原直接路径中增加中间顶点,若加入中间顶点后路径变短,则修改之;否则维持原值。所有顶点试探完毕,算法结束。
2. 代码实现
void ShortestPath_Floyd(Graph G, int** Path, int** D) //Path,D 为二维数组
{
int v, w, k;
for (v = 0; v < G.numv; v++)
{
for (w = 0; w < G.numv; w++)
{
D[v][w] = G.edge[v][w]; //初始化 D 数组为邻接矩阵
//若 v 与 w 之间有弧,将 w 的前驱置为 v
//若 v 与 w 之间没有弧,将 w 的前驱置为 -1
if (D[v][w] < INFINITY)
{
path[v][w] = v;
}
else
{
path[v][w] = -1;
}
}
}
for (k = 0; k < G.numv;k++)
{
for (v = 0; v < G.numv; v++)
{
for(w = 0;w < G.numv; w++)
{
if (D[v][w] > D[v][k] + D[k][w]) //如果从 v 经 k 到 w 的路径最短
{
D[v][w] = D[v][k] + D[k][w];
Path[v][w] = Path[v][k];
}
}
}
}
//显示最短路径
printf("各顶点间最短路径如下:\n");
for(v = 0; v < G.numv; v++)
{
for(w = v+1; w < G.numv; w++)
{
printf("v%d-v%d weight: %d ",v,w,D[v][w]);
k = Path[v][w]; //获得第一个路径的顶点下标
printf(" path: %d",v); //打印源点
while(k != w) //如果路径顶点下标不是终点
{
printf(" -> %d",k); //打印路径顶点
k = Path[k][w]; //获得下一个路径顶点下标
}
printf(" -> %d\n",w); //打印终点
}
printf("\n");
}
}