算法思想:https://www.bilibili.com/video/BV1Ut41197NX?t=715
一,比较
Dijkstra : 是一种解决单源最短路径的算法,即 固定的一个点 到 余下所有点的最短路径
当若 我们要求所有点之间的最短路径呢?
一个方法是:将 Dij 用 n 次,不过这个时间复杂度一下子就到 n的3次方
于是,Floyd 想出了 Floyd算法
Floyd: 解决所有顶点间的最短路径
二,步骤
1,初始化
用 邻接矩阵 ,对角线全为 0
若存在 <vi,vj>, 则为其权值,否则为 无穷大
2,试探
试着在所有路径中,加入中间顶点 Vx,
若路径变小,则改邻接矩阵的值;否则不变
3,循环
试探完所有顶点,算法结束
三,例题 (注意这里是有向图)
四,代码
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<string.h> #define MIN(x,y) (((x)<(y))?(x):(y)) #define inf 0x3f3f3f3f #define N 105 int a[N][N]; int n; void show() { puts(""); for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { printf("%d ", a[i][j]); }puts(""); } } int main(void) { scanf("%d", &n); for (int i = 1; i <= n; i++) //1,初始化 用 邻接矩阵 ,对角线全为 0 若存在 <vi, vj>, 则为其权值,否则为 无穷大 { for (int j = 1; j <= n; j++) a[i][j] = inf; a[i][i] = 0; } int m; scanf("%d", &m); // 边数 while (m--) { int x, y, w; scanf("%d%d%d", &x, &y, &w); a[x][y] = w; } for (int k = 1; k <= n; k++) // 3,循环 试探完所有顶点,算法结束 { for (int i = 1; i <= n; i++) // 2,试探 试着在所有路径中,加入中间顶点 Vx , 若路径变小,则改邻接矩阵的值;否则不变 { for (int j = 1; j <= n; j++) { a[i][j] = MIN(a[i][j], a[i][k] + a[k][j]); } } } show(); system("pause"); return 0; }/* 3 5 1 2 4 2 1 6 1 3 11 3 1 3 2 3 2 */
注意:这里没有存路径
这里的测试数据是上面那个例题。
五,记录路径的方法
用一个数组 p[ i ][ j ] 表示 i 到 j 的最短路径上,终点 j 的前一个的名称。
步骤:
① 初始化
for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) p[i][j] = i; }
② 赋值
for (int k = 1; k <= n; k++) { for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { if (a[i][k] + a[k][j] < a[i][j]) { a[i][j] = a[i][k] + a[k][j]; p[i][j] = p[k][j]; } } } }
③ 打印
这个是重点思想,要讲一下。
假设我们要找A->B的最短路径,那么就依次查找,假设 p[a][b] 的值为 c,即 b 的前一点是 c.
那么接着查找 p[a][c],假设 p[a][c] 的值为 d,
那么接着查找 p[a][d],假设 p[a][d] 的值为 a,则查找结束,最短路径为 a->d->c->b。
void path(int s, int e) { if (p[s][e] != s) path(s, p[s][e]); printf("%d->", p[s][e]); } printf("%d ", e);
注意这里终点是没有打印出来的,需要单独处理。
④ 完整代码
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #define MIN(x,y) (x<y?x:y) #define inf 0x3f3f3f3f #define N 111 int a[N][N]; int p[N][N]; int n, m; void init() { for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { a[i][j] = inf; p[i][j] = i; } a[i][i] = 0; } } void floyd() { for (int k = 1; k <= n; k++) { for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { //a[i][j] = MIN(a[i][j], a[i][k] + a[k][j]); if (a[i][k] + a[k][j] < a[i][j]) { a[i][j] = a[i][k] + a[k][j]; p[i][j] = p[k][j]; } } } } } void path(int s, int e) { if (p[s][e] != s) path(s, p[s][e]); printf("%d->", p[s][e]); } void show() { puts(""); for (int i = 1; i <= n; i++) // 打印 邻接矩阵 { for (int j = 1; j <= n; j++) { printf("%d ", a[i][j]); }puts(""); } for (int i = 1; i <= n; i++) // 求路径 { for (int j = 1; j <= n; j++) { if (i == j) continue; printf("%d 到 %d 的最短路径:", i, j); path(i, j); printf("%d ", j); } } } int main(void) { scanf("%d%d", &n, &m); init(); while (m--) { int u, v, w; scanf("%d%d%d", &u, &v, &w); a[u][v] = w; } floyd(); show(); system("pause"); return 0; }
=========== ======== ========= ======= ====== ===== ==== === == =
If there's any kind of magic in the world, it must be the attempt of understanding someone or share something.
—Before Sunrise
其实最让我们挣扎、绝望的不是困难,而是身边没有一个值得相信的朋友,能让我敞开心扉跟他分享!