【1】为什么需要弗洛伊德算法?
带权图中单个源点到所有顶点的最短路径问题可以用《迪杰斯特拉算法》求解。
那如果要求图中每一个顶点与其它顶点之间的最短路径呢?类似可以想到的方法为:
每次以一个顶点为源点,重复执行地杰斯特拉算法算法n次。
这样,理论上我们便可以求得每一个顶点与其它顶点的最短路径,总的执行时间为O(n3)。
好吧!为了实现这个中需求,可以采用另外一种求解算法:弗洛伊德算法。
为了更好的理解弗洛伊德算法的精妙,我们先看简单的案例。
如下图是一个最简单的3个顶点连通网图:
【2】弗洛伊德算法
弗洛伊德算法是非常漂亮的算法,简洁直观大气上档次。
不过很可惜由于它的三重循环,因此也是O(n*n*n)的时间复杂度。
如果你面临需要求所有顶点至所有顶点的最短路径问题?
它是很好的选择。算法代码如下图:
关于本算法再不做详细赘述。如若感兴趣,下面的代码案例可以自己琢磨琢磨。
【3】弗洛伊德算法实现
注意:本算法的实现案例与迪杰斯特拉算法相同都是在求同一个图的最短路径问题。
不同的是这个算法可以求得所有顶点到所有顶点的最短路径。
模拟实现代码如下:
#include <iostream>
#include "SeqList.h"
#include <iomanip>
using namespace std;
#define INFINITY 65535
typedef int* pInt;
typedef pInt* ppInt;
template<class NameType, class DistType>
class Graph
{
private:
SeqList<NameType> Vertices;
DistType **Edges;
int nVer, nEdges;
public:
Graph()
: Edges(NULL)
, nEdges(0)
, nVer(0)
{}
~Graph()
{}
public:
int GetVer() const
{
return nVer;
}
istream & operator>>(istream &in)
{
int v, u, value;
int i, j;
NameType item;
cout << "请输入顶点的个数: " << endl;
in >> nVer;
cout << "请输入顶点的数据信息: " << endl;
for (i = 0; i < nVer; ++i)
{
in >> item;
Vertices.push_back(item); // 保存全部顶点
}
/二维数组的创建并初始化
Edges = new DistType*[nVer]; // DistType *ar[10];
for (i = 0; i < nVer; ++i)
{
Edges[i] = new DistType[nVer];
for (j = 0; j < nVer; ++j)
{
Edges[i][j] = 0;
}
}
cout << "请输入边的个数: " << endl;
in >> nEdges;
cout << "请输入边的信息:" << endl;
for (i = 0; i < nEdges; ++i)
{
in >> v >> u >> value;
Edges[v][u] = value;
Edges[u][v] = value;
}
return in;
}
ostream & operator<<(ostream &out) const
{
int i, j;
out << "顶点信息 " << endl;
for (i = 1; i <= nVer; ++i)
{
out << Vertices[i] << setw(5);
}
out << endl;
out << "矩阵信息:" << endl;
out << setw(10);
for (i = 1; i <= nVer; ++i)
{
out << Vertices[i] << setw(5);
}
out << endl;
for (i = 0; i < nVer; ++i)
{
out << Vertices[i+1] << setw(5);
for (j = 0; j < nVer; ++j)
{
if (0 == Edges[i][j] && i != j)
Edges[i][j] = INFINITY;
cout << Edges[i][j] << setw(5);
}
out << endl;
}
out << endl;
return out;
}
// 弗洛伊德算法实现
void ShortestPath_Floyd(int** p, int** D)
{
int v = 0, w = 0, k = 0;
// 初始化数据
for (v = 0; v < nVer; ++v)
{
for (w = 0; w < nVer; ++w)
{
D[v][w] = Edges[v][w];
p[v][w] = w;
}
}
for (k = 0; k < nVer; ++k)
{
for (v = 0; v < nVer; ++v)
{
for(w = 0; w < nVer; ++w)
{
if (D[v][w] > D[v][k] + D[k][w])
{
D[v][w] = D[v][k] + D[k][w];
p[v][w] = p[v][k];
}
}
}
}
}
// 打印矩阵信息
void PrintArray(ppInt pp)
{
cout << setw(10);
for (int i = 1; i <= nVer; ++i)
{
cout << Vertices[i] << setw(5);
}
cout << endl;
for (int i = 0; i < nVer; ++i)
{
cout << Vertices[i+1] << setw(5);
for (int j = 0; j < nVer; ++j)
{
cout << pp[i][j] << setw(5);
}
cout << endl;
}
cout << endl;
}
// 求解完成后打印所以路径信息
void PrintPath(ppInt pp, ppInt DD)
{
int v, k, w;
for (v = 0; v < nVer; ++v)
{
for (w = v+1; w < nVer; ++w)
{
cout << "V" << v << "-->" << "V" << w << " weight:" << DD[v][w] << endl;
k = pp[v][w];
cout << "Path:V" << v;
while (k != w)
{
cout << "-->V" << k;
k = pp[k][w];
}
cout << "-->V" << w << endl;
}
}
cout << endl;
}
};
template<class NameType, class DistType>
istream & operator>>(istream &in, Graph<NameType,DistType> &g)
{
g >> in;
return in;
}
template<class NameType, class DistType>
ostream & operator<<(ostream &out, const Graph<NameType,DistType> &g)
{
g << out;
return out;
}
void main()
{
Graph<char, int> myg;
cin >> myg;
cout << "打印所有输入信息:" << endl;
cout << myg << endl;
cout << "求最短路径....." << endl;
int numVer = myg.GetVer();
ppInt pPathmatirx = new pInt[numVer];
for (int i = 0; i < numVer; ++i)
{
pPathmatirx[i] = new int[numVer];
for (int j = 0; j < numVer; ++j)
{
pPathmatirx[i][j] = 0;
}
}
ppInt pShortPath = new pInt[numVer];
for (int i = 0; i < numVer; ++i)
{
pShortPath[i] = new int[numVer];
for (int j = 0; j < numVer; ++j)
{
pShortPath[i][j] = 0;
}
}
myg.ShortestPath_Floyd(pPathmatirx, pShortPath);
cout << "分别打印矩阵结果:" << endl;
cout << "各顶点最短路径:" << endl;
myg.PrintArray(pShortPath);
cout << "各最短路径前驱顶点下标值:" << endl;
myg.PrintArray(pPathmatirx);
cout << "打印全部最短路径:"<< endl;
myg.PrintPath(pPathmatirx, pShortPath);
// 释放二维数组
for (int i = 0; i < numVer; ++i)
delete []pPathmatirx[i];
delete []pPathmatirx;
for (int i = 0; i < numVer; ++i)
delete []pShortPath[i];
delete []pShortPath;
pPathmatirx = NULL;
pShortPath = NULL;
}
// 备注:
// 最短路径弗洛伊德算法实现
// 整理于2013-12-05
// 测试输入程序为:
/*
请输入顶点的个数:
9
请输入顶点的数据信息:
A B C D E F G H I
请输入边的个数:
16
请输入边的信息:
0 1 1
0 2 5
1 2 3
1 3 7
1 4 5
2 4 1
2 5 7
3 4 2
3 6 3
4 5 3
4 6 6
4 7 9
5 7 5
6 7 2
6 8 7
7 8 4
打印所有输入信息:
顶点信息
A B C D E F G H I
矩阵信息:
A B C D E F G H I
A 0 1 5655356553565535655356553565535
B 1 0 3 7 565535655356553565535
C 5 3 065535 1 7655356553565535
D65535 765535 0 265535 36553565535
E65535 5 1 2 0 3 6 965535
F6553565535 765535 3 065535 565535
G655356553565535 3 665535 0 2 7
H65535655356553565535 9 5 2 0 4
I655356553565535655356553565535 7 4 0
求最短路径.....
分别打印矩阵结果:
各顶点最短路径:
A B C D E F G H I
A 0 1 4 7 5 8 10 12 16
B 1 0 3 6 4 7 9 11 15
C 4 3 0 3 1 4 6 8 12
D 7 6 3 0 2 5 3 5 9
E 5 4 1 2 0 3 5 7 11
F 8 7 4 5 3 0 7 5 9
G 10 9 6 3 5 7 0 2 6
H 12 11 8 5 7 5 2 0 4
I 16 15 12 9 11 9 6 4 0
各最短路径前驱顶点下标值:
A B C D E F G H I
A 0 1 1 1 1 1 1 1 1
B 0 1 2 2 2 2 2 2 2
C 1 1 2 4 4 4 4 4 4
D 4 4 4 3 4 4 6 6 6
E 2 2 2 3 4 5 3 3 3
F 4 4 4 4 4 5 7 7 7
G 3 3 3 3 3 7 6 7 7
H 6 6 6 6 6 5 6 7 8
I 7 7 7 7 7 7 7 7 8
打印全部最短路径:
V0-->V1 weight:1
Path:V0-->V1
V0-->V2 weight:4
Path:V0-->V1-->V2
V0-->V3 weight:7
Path:V0-->V1-->V2-->V4-->V3
V0-->V4 weight:5
Path:V0-->V1-->V2-->V4
V0-->V5 weight:8
Path:V0-->V1-->V2-->V4-->V5
V0-->V6 weight:10
Path:V0-->V1-->V2-->V4-->V3-->V6
V0-->V7 weight:12
Path:V0-->V1-->V2-->V4-->V3-->V6-->V7
V0-->V8 weight:16
Path:V0-->V1-->V2-->V4-->V3-->V6-->V7-->V8
V1-->V2 weight:3
Path:V1-->V2
V1-->V3 weight:6
Path:V1-->V2-->V4-->V3
V1-->V4 weight:4
Path:V1-->V2-->V4
V1-->V5 weight:7
Path:V1-->V2-->V4-->V5
V1-->V6 weight:9
Path:V1-->V2-->V4-->V3-->V6
V1-->V7 weight:11
Path:V1-->V2-->V4-->V3-->V6-->V7
V1-->V8 weight:15
Path:V1-->V2-->V4-->V3-->V6-->V7-->V8
V2-->V3 weight:3
Path:V2-->V4-->V3
V2-->V4 weight:1
Path:V2-->V4
V2-->V5 weight:4
Path:V2-->V4-->V5
V2-->V6 weight:6
Path:V2-->V4-->V3-->V6
V2-->V7 weight:8
Path:V2-->V4-->V3-->V6-->V7
V2-->V8 weight:12
Path:V2-->V4-->V3-->V6-->V7-->V8
V3-->V4 weight:2
Path:V3-->V4
V3-->V5 weight:5
Path:V3-->V4-->V5
V3-->V6 weight:3
Path:V3-->V6
V3-->V7 weight:5
Path:V3-->V6-->V7
V3-->V8 weight:9
Path:V3-->V6-->V7-->V8
V4-->V5 weight:3
Path:V4-->V5
V4-->V6 weight:5
Path:V4-->V3-->V6
V4-->V7 weight:7
Path:V4-->V3-->V6-->V7
V4-->V8 weight:11
Path:V4-->V3-->V6-->V7-->V8
V5-->V6 weight:7
Path:V5-->V7-->V6
V5-->V7 weight:5
Path:V5-->V7
V5-->V8 weight:9
Path:V5-->V7-->V8
V6-->V7 weight:2
Path:V6-->V7
V6-->V8 weight:6
Path:V6-->V7-->V8
V7-->V8 weight:4
Path:V7-->V8
*/
扫码关注本人微信公众号,有惊喜奥!公众号每天定时发送精致文章!回复关键词可获得海量各类编程开发学习资料!
例如:想获得Python入门至精通学习资料,请回复关键词Python即可。