转载自博客园
【1】为什么需要弗洛伊德算法?
带权图中单个源点到所有顶点的最短路径问题可以用迪杰斯特拉算法求解。
那如果要求图中每一个顶点与其它顶点之间的最短路径呢?类似可以想到的方法为:
每次以一个顶点为源点,重复执行地杰斯特拉算法算法n次。
这样,理论上我们便可以求得每一个顶点与其它顶点的最短路径,总的执行时间为O(n3)。
好吧!为了实现这个中需求,可以采用另外一种求解算法:弗洛伊德算法。
为了更好的理解弗洛伊德算法的精妙,我们先看简单的案例。
如下图是一个最简单的3个顶点连通网图:
【2】弗洛伊德算法
弗洛伊德算法是非常漂亮的算法,简洁直观大气上档次。
不过很可惜由于它的三重循环,因此也是O(n*n*n)的时间复杂度。
如果你面临需要求所有顶点至所有顶点的最短路径问题?
它是很好的选择。算法代码如下图:
关于本算法再不做详细赘述。如若感兴趣,下面的代码案例可以自己琢磨琢磨。
【3】弗洛伊德算法实现
注意:本算法的实现案例与迪杰斯特拉算法相同都是在求同一个图的最短路径问题。
不同的是这个算法可以求得所有顶点到所有顶点的最短路径。
模拟实现代码如下:
#include <iostream>
#include <cstdio>
#include <stack>
#define veNum 6
#define INT_MAX 1000000
using namespace std;
int main()
{
//int G[veNum][veNum] = {0, 4, 11, 6, 0, 2, 3, INT_MAX, 0};
//int G[6][6];
int G[veNum][veNum] = {INT_MAX, INT_MAX, 10, INT_MAX, 30, 100,
INT_MAX, INT_MAX, 5, INT_MAX, INT_MAX, INT_MAX,
INT_MAX, INT_MAX, INT_MAX, 50, INT_MAX, INT_MAX,
INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, 10,
INT_MAX, INT_MAX, INT_MAX, 20, INT_MAX, 60,
INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX};
stack<int> S;
int P[veNum][veNum];
int D[veNum][veNum];
//初始化
for (int i = 0; i < veNum; i ++)
{
for (int j = 0; j < veNum; j ++)
{
P[i][j] = i;
D[i][j] = G[i][j];
}
}
//核心算法
for (int i = 0; i < veNum; i ++)
{
for (int j = 0; j < veNum; j ++)
{
for (int k = 0; k < veNum; k ++)
{
if (D[i][j] > D[i][k] + D[k][j])
{
D[i][j] = D[i][k] + D[k][j];
P[i][j] = k;
}
}
}
}
for (int i = 0; i < veNum; i ++)
{
for (int j = 0; j < veNum; j ++)
{
cout << G[i][j] << " ";
}
cout << endl;
}
cout << endl << endl << "最短路径:" << endl;
for (int j = 0; j < veNum; j ++)
{
for (int i = 0; i < veNum; i ++)
{
if (i != j)
{
cout << "V" << j << "-->V" << i << ": " << D[j][i] << endl;
cout << "\tV" << j << "-->";
int temp = i;
while (temp != j)
{
S.push(temp);
temp = P[j][temp];
}
while(S.size() > 1)
{
cout << "V" << S.top() << "-->";
S.pop();
}
cout << "V" << S.top() << endl;
S.pop();
cout << endl;
}
}
}
system("pause");
return 0;
}