上一次的最短路径dijkstra算法精品代码(超详解)
Floyd-Warshall算法,简称Floyd算法,用于求解任意两点间的最短距离,时间复杂度为O(n^3)。
使用条件&范围
通常可以在任何图中使用,包括有向图、带负权边的图。
Floyd-Warshall 算法用来找出每对点之间的最短距离。它需要用邻接矩阵来储存边,这个算法通过考虑最佳子路径来得到最佳路径。
1.注意单独一条边的路径也不一定是最佳路径。
2.从任意一条单边路径开始。所有两点之间的距离是边的权,或者无穷大,如果两点之间没有边相连。
对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比己知的路径更短。如果是更新它。
3.不可思议的是,只要按排适当,就能得到结果。
代码说明几点:
1、A[][]数组初始化为各顶点间的原本距离,最后存储各顶点间的最短距离。
2、path[][]数组保存最短路径,与当前迭代的次数有关。初始化都为-1,表示没有中间顶点。在求A[i][j]过程中,path[i][j]存放从顶点vi到顶点vj的中间顶点编号不大于k的最短路径上前一个结点的编号。在算法结束时,由二维数组path的值回溯,可以得到从顶点vi到顶点vj的最短路径。
初始化A[][]数组为如下,即有向图的邻接矩阵。
代码如下:
#include <iostream>
#include <cstring>
#include <stack>
using namespace std;
#define MAX 100
#define INF 0x3f3f3f3f
struct MGraph
{
int edges[MAX][MAX];//邻接矩阵,记录的是两点之间的距离,也就是权值
int n,e;//顶点数和边数
}G;
int path[MAX][MAX];//记录当前两顶点间最短路径上要经过的中间点
void init() {
memset(G.edges, INF, sizeof(G.edges));//默认为INF
for(int i = 0; i < MAX; i++){ //顶点到它本身的距离设置为0
G.edges[i][i] = 0;
}
}
void insert(int u, int v, int w) {
G.edges[u][v] = w;//
}
void printfPath(int u, int v, int path[][MAX]){ //输出从u到v的最短路径上顶点序列
cout << u << "->";
while(path[u][v] != -1){
cout << path[u][v] << "->";
u = path[u][v];
}
cout << v;
}
void Floyd(MGraph G, int path[][MAX]){ //顶点默认从0到n
int i, j, k;
int A[MAX][MAX];
//这个双循环对数组A和path进行了初始化
for(i = 0; i < G.n; i++){
for(j = 0; j < G.n; j++){
A[i][j] = G.edges[i][j];
path[i][j] = -1;
}
}
//下面三个循环是本算法的主要操作,完成了以k为中间点对所有的顶点对{i, j}进行检测和修改
for(k = 0; k < G.n; k++){ //选中的中间值
for(i = 0; i < G.n; i++){ //数组横坐标
for(j = 0; j < G.n; j++){ //数组纵坐标
if(A[i][j] > A[i][k] + A[k][j]){ //如果以k中间点为中间点检测到路径更短
A[i][j] = A[i][k] + A[k][j]; //更新路径值
path[i][j] = k; //更新要经过的中间点
}
}
}
}
}
int main() {
init();
int n, m;//n个点,m条边
int a, x, y, w;
cin >> m >> n;
G.e = m;
G.n = n;
for(int i = 0; i < m; i++){
cin >> x >> y >> w;
insert(x, y, w);
}
Floyd(G, path);
int u, v;
cin >> u >> v;
printfPath(u, v, path);
return 0;
}
/*测试数据
8 4
0 1 5
0 3 7
1 2 4
1 3 2
2 0 3
2 1 3
2 3 2
3 2 1
*/