弗洛伊德(Floyd)算法求图的最短路径「建议收藏」

弗洛伊德(Floyd)算法求图的最短路径「建议收藏」弗洛伊德基本思想弗洛伊德算法作为求最短路径的经典算法,其算法实现相比迪杰斯特拉等算法是非常优雅的,可读性和理解都非常好。基本思想:弗洛伊德算法定义了两个二维矩阵:矩阵D记录顶点间的最小路径例如D[0][3]=10,说明顶点0到3的最短路径为10;矩阵P记录顶点间最小路径中的中转点例如P[0][3]=1说明,0到3的最短路径轨迹为:

大家好,又见面了,我是你们的朋友全栈君。

弗洛伊德基本思想

弗洛伊德算法作为求最短路径的经典算法,其算法实现相比迪杰斯特拉等算法是非常优雅的,可读性和理解都非常好。

基本思想:
弗洛伊德算法定义了两个二维矩阵:

  1. 矩阵D记录顶点间的最小路径
    例如D[0][3]= 10,说明顶点0 到 3 的最短路径为10;
  2. 矩阵P记录顶点间最小路径中的中转点
    例如P[0][3]= 1 说明,0 到 3的最短路径轨迹为:0 -> 1 -> 3。

它通过3重循环,k为中转点,v为起点,w为终点,循环比较D[v][w] 和 D[v][k] + D[k][w] 最小值,如果D[v][k] + D[k][w] 为更小值,则把D[v][k] + D[k][w] 覆盖保存在D[v][w]中。

概念是比较难理解的,我们来看图:

这里写图片描述

顶点名称和下标的对应
A B C D E F G
0 1 2 3 4 5 6

第2步:
以A为中间点,原D矩阵中,D[B][G]的值为INF,即不存在B->G的最小路径,但是通过A为中间点,D[B][A] + D[A][G] = 12 + 14 = 26 小于 D[B][G] = INF, 所以D[B][A] + D[A][G] 为 B -> G的最小值,因此覆盖D[B][G] 为 26。

第3步:
以B为中间点,第2步后的D矩阵中,D[A][C]的值为INF, 但是通过B,D[A][B] + D[B][C] = 12 + 10 = 22 小于 D[A][C] = INF,所以D[A][B] + D[B][C] 为 A->C的最小路径,覆盖D[A][C]的值为22, 以此类推。

第4步….

代码实现

我们就对上面的图进行弗洛伊德算法求最短路径,并且我们求A到D的最小路径,即v = 0, w = 3;

结构定义

typedef struct struct_graph{
    char vexs[MAXN];
    int vexnum;//顶点数 
    int edgnum;//边数 
    int matirx[MAXN][MAXN];//邻接矩阵 
} Graph;

弗洛伊德算法

//这里是弗洛伊德算法的核心部分 
    //k为中间点 
    for(k = 0; k < G.vexnum; k++){
        //v为起点 
        for(v = 0 ; v < G.vexnum; v++){
            //w为终点 
            for(w =0; w < G.vexnum; w++){
                if(D[v][w] > (D[v][k] + D[k][w])){
                    D[v][w] = D[v][k] + D[k][w];//更新最小路径 
                    P[v][w] = P[v][k];//更新最小路径中间顶点 
                }
            }
        }
    }

求A 到 D的最短路径

    v = 0;
    w = 3;
    //03的最小路径
    printf("\n%d -> %d 的最小路径为:%d\n", v, w, D[v][w]);
    k = P[v][w];
    printf("path: %d", v);//打印起点
    while(k != w){
        printf("-> %d", k);//打印中间点
        k = P[k][w]; 
    }
    printf("-> %d\n", w);

完整代码

#include <stdio.h>
#include <stdlib.h>

#define MAXN 10 
#define INF = 1000

typedef struct struct_graph{
    char vexs[MAXN];
    int vexnum;//顶点数 
    int edgnum;//边数 
    int matirx[MAXN][MAXN];//邻接矩阵 
} Graph;

int pathmatirx[MAXN][MAXN];//记录对应点的最小路径的前驱点,例如p(1,3) = 2 说明顶点1到顶点3的最小路径要经过2 
int shortPath[MAXN][MAXN];//记录顶点间的最小路径值

void short_path_floyd(Graph G, int P[MAXN][MAXN], int D[MAXN][MAXN]){
    int v, w, k;
    //初始化floyd算法的两个矩阵 
    for(v = 0; v < G.vexnum; v++){
        for(w = 0; w < G.vexnum; w++){
            D[v][w] = G.matirx[v][w];
            P[v][w] = w;
        }
    }

    //这里是弗洛伊德算法的核心部分 
    //k为中间点 
    for(k = 0; k < G.vexnum; k++){
        //v为起点 
        for(v = 0 ; v < G.vexnum; v++){
            //w为终点 
            for(w =0; w < G.vexnum; w++){
                if(D[v][w] > (D[v][k] + D[k][w])){
                    D[v][w] = D[v][k] + D[k][w];//更新最小路径 
                    P[v][w] = P[v][k];//更新最小路径中间顶点 
                }
            }
        }
    }

    printf("\n初始化的D矩阵\n");
    for(v = 0; v < G.vexnum; v++){
        for(w = 0; w < G.vexnum; w++){
            printf("%d ", D[v][w]);
        }
        printf("\n");
    }

    printf("\n初始化的P矩阵\n");
    for(v = 0; v < G.vexnum; v++){
        for(w = 0; w < G.vexnum; w++){
            printf("%d", P[v][w]);
        }
        printf("\n");
    }

    v = 0;
    w = 3;
    //求 0 到 3的最小路径
    printf("\n%d -> %d 的最小路径为:%d\n", v, w, D[v][w]);
    k = P[v][w];
    printf("path: %d", v);//打印起点
    while(k != w){
        printf("-> %d", k);//打印中间点
        k = P[k][w]; 
    }
    printf("-> %d\n", w);
}

int main(){
    int v, w;
    Graph G;
    printf("请输入顶点数:\n");
    scanf("%d", &G.vexnum);
    printf("请输入初始矩阵值:\n");
    for(v = 0; v < G.vexnum; v++){
        for(w = 0; w < G.vexnum; w++){
            scanf("%d", &G.matirx[v][w]);
        }
    }
    printf("\n输入的矩阵值:\n");
    for(v = 0; v < G.vexnum; v++){
        for(w = 0; w < G.vexnum; w++){
            printf("%d ", G.matirx[v][w]);
        }
        printf("\n");
    }
    short_path_floyd(G, pathmatirx, shortPath);
}

操作结果

初始化操作

这里写图片描述

弗洛伊德算法后的D矩阵和P矩阵

这里写图片描述

求得的最短路径

这里写图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/136055.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • vue集成activiti工作流_vue 异步渲染

    vue集成activiti工作流_vue 异步渲染一、安装px2rem-loadernpminstallpx2rem-loader二、配置build文件夹下utils.js,找到generateLoaders 修改如下配置constpx2remLoader={loader:’px2rem-loader’,options:{remUnit:75//设计稿宽度/10}…

    2025年7月4日
    0
  • linux常用命令

    linux常用命令linux常用命令

    2022年4月25日
    41
  • python编程考试有哪些(python编程考试模拟题)

    python编程考试有哪些(python编程考试模拟题)2021国内外主流机器人编程赛事+等级考试Scratch编程、C++编程、Python编程等多个赛项,评比类、竞技类不同比赛形式自主选择。多个国内外主流机器人编程赛事,总能帮助孩子找到施展能力、表现创意的舞台。机器人、编程、人工智能等级考试篇全国青少年机器人技术等级考试和全国青少年软件编程等级考试均由中国电子…。2021机器人编程赛事+等级考试攻略之国内外主流赛事及能力测评篇上周,玛酷在公众号发布了一篇名为《2021机器人编程赛事+等级考试攻略之教育部白名单赛事篇》的文章。文章中为大家介绍了20

    2022年5月17日
    62
  • 电平转换的作用_电平转换电路原理

    电平转换的作用_电平转换电路原理作为一名电子设计的硬件工程师,电平转换是每个人都必须面对的的话题,主芯片引脚使用的1.2V、1.8V、3.3V等,连接外部接口芯片使用的1.8V、3.3V、5V等,由于电平不匹配就必须进行电平转换。每个工程师都有自己的一套转换方案,今天我们将5种电平转换的方法进行汇总,并且总结各种的优劣势,避免设计过程踩坑。一、电平转换方法5种电平转换方法分别是:晶体管电平转换方法;专用电平转换芯片;限流电阻电平转换方法;电阻分压电平转换方法;二极管电平转换方法;下面我们会从速率、驱动能力、漏电流、成本

    2022年8月10日
    6
  • AMD FreeSync显示器上市,这是要把G-Sync虐成渣了「建议收藏」

    AMD FreeSync显示器上市,这是要把G-Sync虐成渣了「建议收藏」玩家玩个游戏也真不容易,配置低的怕卡顿,配置高了帧数漂亮,但又怕画面撕裂,开垂直同步倒是可以解决部分问题,但帧数限制死了又让人觉得很不爽。对于这个问题,NVIDIA2013年10月份推出了G-Sync技术,AMD随后推出了FreeSync技术与之竞争,现在双方的G-Sync及FreeSync显示器都上市了,一场大战是免不了的。这一年半以来,G-Sync与FreeSync虽然没有真

    2022年6月5日
    62
  • c++实现远程开关机「建议收藏」

    c++实现远程开关机「建议收藏」把远程开、关机写成了一个类的两个静态函数。这两个功能的实现都需要事先对目标主机进行一些设置。其中远程开机需要目标主机主板支持,并且插上网线。部分主机的设置已经写明。另可实现方法:https://www.cnblogs.com/findumars/p/6009474.html原理参考:https://blog.csdn.net/smstong/article/details/16879347…

    2022年6月2日
    32

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号