最短路径2:Floyd算法

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值