Floyd算法
基本思想:
对于弧<vi,vj>,进行n次试探:首先考虑路径<vi,v0,vj>是否存在,如果存在,则比较<vi,vj>和<vi,v0,vj>的路径长度,取较短者为从vi到vj的中间顶点的序号不大于0的最短路径。在路径上再增加一个顶点v1,依此类推,在经过n次比较后,最后求得的必是从顶点vi到顶点vj的最短路径。
通常可以在任何图中使用,包括有向图、带负权边的图。时间复杂度为O(n3)
数据结构:带权的邻接矩阵存储结构
path[i][j]:存放从vi到vj的最短路径,初始为path[i][j]=“vivj”。
dist[i][j]:存放在迭代过程中求得的最短路径长度。
迭代公式:
dist-1[i][j] = Graph[i][j]
distk[i][j] = min{ distk-1[i][j] , distk-1[i][k]+distk-1[k][j]} (0≤k≤n-1)
具体过程:
第一步:以顶点A为中介点
dist[B][G] = INF,dist[B][A] + dist[A][G] = 12+14 = 26
第二步:以顶点B为中介点
dist[A][C] = INF,dist[A][B] + dist[B][C] = 12+10 = 22
dist[C][G] = INF,dist[C][B] + dist[B][G] = 10+26 = 36
第三步:以顶点C为中介点
dist[A][D] = INF,dist[A][C] + dist[C][D] = 22+3 = 25
dist[A][E] = INF,dist[A][C] + dist[C][E] = 22+5 = 27
dist[B][D] = INF,dist[B][C] + dist[C][D] = 10+3 = 13
dist[B][E] = INF,dist[B][C] + dist[C][E] = 10+5 = 15
dist[D][F] = INF,dist[D][C] + dist[C][F] = 3+6 = 9
dist[D][G] = INF,dist[D][C] + dist[C][G] = 3+36 = 39
第四步:以顶点D为中介点
dits[]
第五步:以顶点E为中介点
dist[B][G] = 26,dist[B][E] + dist[E][G] = 15+8 = 23
dist[C][G] = 36,dist[C][E] + dist[E][G] = 5+8 = 13
dist[D][F] = 9, dist[D][E] + dist[E][F] = 4+2 = 6
dist[D][G] = 39,dist[D][E] + dist[E][G] = 4+8 = 12
第六步:以顶点F为中介点
dist[A][D] = 25,dist[A][F] + dist[F][D] = 16+6 = 22
dist[A][E] = 27,dist[A][F] + dist[F][E] = 16+2 = 18
dist[B][E] = 15,dist[B][F] + dist[F][E] = 7+2 = 9
dist[B][G] = 23,dist[B][F] + dist[F][G] = 7+9 = 16
//A0 B1 C2 D3 E4 F5 G6
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXN 10
#define Inf 0x3f3f3f3f
typedef struct struct_graph{
char vexs[MAXN];
int vexnum;//顶点数
int edgnum;//边数
int matirx[MAXN][MAXN];//邻接矩阵
} Graph;
int path[MAXN][MAXN];//记录对应点的最小路径的前驱点。例如 path[1][3] = 2,说明顶点1到顶点3的最小路径要经过2。
int dist[MAXN][MAXN];//记录顶点间的最小路径值
void floyd(Graph G){
//初始化floyd算法的两个矩阵
for(int u = 0; u < G.vexnum; ++u){
for(int v = 0; v < G.vexnum; ++v){
dist[u][v] = G.matirx[u][v];
path[u][v] = v;
}
}
//这里是弗洛伊德算法的核心部分
for(int k = 0; k < G.vexnum; ++k){//k为中间点
for(int u = 0 ; u < G.vexnum; ++u){
for(int v =0; v < G.vexnum; ++v){
if(dist[u][v] > dist[u][k] + dist[k][v]){
dist[u][v] = dist[u][k] + dist[k][v];//更新最小路径值
path[u][v] = path[u][k];//更新最小路径中间顶点
}
}
}
}
//输出两个矩阵的运算结果
printf("\nFloyd运算后:dist[][]\n");
for(int u = 0; u < G.vexnum; ++u){
for(int v = 0; v < G.vexnum; ++v)
printf("%d\t", dist[u][v]);
putchar('\n');
}
printf("\nFloyd运算后:path[][]\n");
for(int u = 0; u < G.vexnum; ++u){
for(int v = 0; v < G.vexnum; ++v)
printf("%d\t", path[u][v]);
putchar('\n');
}
//输出最短路径值和最短路径经过的顶点
int u = 0, v = 3;
printf("\n%d -> %d 的最小路径为:%d\n", u, v, dist[u][v]);
int k = path[u][v];//最短路径
printf("path: %d", u);//打印起点
while(k != v){
printf(" -> %d", k);//打印中间点
k = path[k][v];
}
printf("-> %d\n", v);//打印终点
}
void shortestpath(){
}
int main(){
Graph G;
printf("请输入顶点数和边数:\n");
scanf("%d%d", &G.vexnum, &G.edgnum);
//初始化图G
memset(G.matirx, Inf, sizeof(G.matirx));
for(int i = 0; i < G.vexnum; ++i)
G.matirx[i][i] = 0;
for(int i = 0; i < G.edgnum; ++i) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
G.matirx[u][v] = G.matirx[v][u] = w;
}
printf("\n初始化后:图G\n");
for(int u = 0; u < G.vexnum; ++u){
for(int v = 0; v < G.vexnum; ++v){
G.matirx[u][v] == Inf ? printf("#\t") : printf("%d\t", G.matirx[u][v]);
}
putchar('\n');
}
floyd(G);
return 0;
}
7 12
0 1 12
0 5 16
0 6 14
1 2 10
1 5 7
2 3 3
2 4 5
2 5 6
3 4 4
4 5 2
4 6 8
5 6 9