Floyd算法是求加权图最短路径的经典算法之一,利用了动态规划的思想解决。
算法描述
最短路径问题:
设有一加权图G,从G中某个顶点出发达到另一个顶点,所经过边的权值之和最小的路径,被称为最短路径。
Floyd算法是解决加权图(图可以是有向也可以是无向,可以存在负权)中任意两点之间的最单路径的一种算法。
基本思路:
通过Floyd算法计算最短路径时,图一般采用二维数组,邻接矩阵的形式进行存储。
首先对邻接矩阵进行初始化,在图G中,g[i][j g[i][jg[i][j]表示从顶点i到顶点j的直接路径(权值);若i和j不相邻,即无直接连线,则置g[i][j]=∞ g[i][j]= ∞g[i][j]=∞;且设g[i][i]=0 g[i][i]=0g[i][i]=0,即顶点i到顶点i的距离为0;
寻找最短距离的过程就是对邻接矩阵进行更新的过程:若从顶点i到顶点j经过顶点k,且g[i][j]>g[i][k]+g[k][j] g[i][j] > g[i][k] + g[k][j]g[i][j]>g[i][k]+g[k][j],则从i到j的最短距离更新为从i到k再到j;
对图进行n次更新,遍历i,j,k的值,找到最短路径;
从上面我们可以看到Floyd算法的时间复杂度为O(n3)。
源代码运行结果参照此图
源代码
#include <iostream>
#include <vector>
#define MAX 9999
using namespace std;
//弗洛伊德算法
void Floyd(vector<vector<int> > &g, vector<vector<int> > &p) {
int n = g.size(); //图的顶点数+1
for (int i = 1; i < n; i++) {
for (int j = 1; j < n; j++) {
if (i == j) //相同顶点
continue;
for (int k = 1; k < n; k++) {
if (g[i][j] > g[i][k] + g[k][j]) { //从顶点i到j经过k,且dij > dik + dkj
g[i][j] = g[i][k] + g[k][j];
p[i][j] = k;
}
}
}
}
}
//打印路径
void printPath(vector<vector<int> > &p, int a, int b) {
int k = p[a][b];
if (k == -1)
return;
printPath(p, a, k);
cout << "-> " << k;
printPath(p, k, b);
}
int main() {
int vexNum, edgeNum;
cout << "输入顶点数量和边的数量:";
cin >> vexNum >> edgeNum;
//建立邻接矩阵并初始化
vector<vector<int> > graph(vexNum + 1, vector<int> (vexNum + 1,MAX)); //图的邻接矩阵
vector<vector<int> > path(vexNum + 1, vector<int>(vexNum + 1, -1)); //路径矩阵
//初始化图
for (int i = 1; i <= vexNum; i++)
graph[i][i] = 0;
cout << "输入邻接边及权值:(边a 边b 权值w)" << endl;
for (int i = 0; i < edgeNum; i++) {
int a, b, w;
cin >> a >> b >> w;
graph[a][b] = w;
}

Floyd(graph,path); //弗洛伊德算法
int a, b;
cout << "输入你要查询的最短路径 a->b:(顶点a 顶点b)";
cin >> a >> b;
if (graph[a][b] == MAX)
cout << "从" << a << "到" << b << "没有路径。" << endl;
cout << "从" << a << "到" << b << "最短路径为:" << graph[a][b] << endl;
cout << a;
printPath(path, a, b);
cout << "-> " << b << endl;
system("pause");
return 0;
}