[ 数据结构 ] 弗洛伊德算法(Floyd)--------最短路径问题

news2024/11/28 6:32:35

0 Floyd算法介绍

  1. 和 Dijkstra 算法一样,弗洛伊德(Floyd)算法也是一种用于寻找给定的加权图中顶点间最短路径的算法。该算法名称以创始人之一、1978 年图灵奖获得者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名
  2. 弗洛伊德算法(Floyd)计算图中各个顶点之间的最短路径
  3. 迪杰斯特拉算法用于计算图中某一个顶点到其他顶点的最短路径。
  4. 弗洛伊德算法 VS 迪杰斯特拉算法:迪杰斯特拉算法通过选定的被访问顶点,求出从出发访问顶点到其他顶点的最短路径;弗洛伊德算法中每一个顶点都是出发访问点,所以需要将每一个顶点看做被访问顶点,求出从每一个顶点到其他顶点的最短路径。
  5. 回顾:迪杰斯特拉算法

1 Floyd算法应用

image-20230109204119269.png

最短路径问题:

  1. 胜利乡有 7 个村庄(A, B, C, D, E, F, G)
  2. 各个村庄的距离用边线表示(权) ,比如 A – B 距离 5 公里
  3. 问:如何计算出各村庄到 其它各村庄的最短距离?

思路分析:

  1. 核心思想:穷举
  2. 三层for循环分别使3个指针指向三个顶点,最外层表示中间顶点k
  3. k=0则表示A顶点作为中间顶点,那么就可以更新BC和CG间的最短路径
  4. k从0->6,则可以得到所有顶点间的最短路径
  5. 当然想法简单,但是实现起来需要借助辅助变量,这里用到初始值为邻接矩阵的距离表dis和初始值为出发点的前驱关系表pre

image-20230109235216136.png

image-20230109235233631.png

个人理解:

  1. 为什么如此初始化前驱关系表?

    因为默认开始只有两种路线:直连/不直连,两种情况下默认前驱节点都是出发点,即出发点到任何顶点的前驱节点都是自己,至于后续的改动,不管最短路线改为非直连的两段还是三段,也只是针对不直连的路(即65535),而直连的两个顶点相关数据无需改动,前驱自然就是终点的前驱节点,即出发点

  2. 两顶点之间非直连,最短路径为3段的,最短路径是怎么更新的,如CD的最短路径为CEFD?

    观察:虽然F作为中间点,但是测试时中间点第一个就用F,CD的距离和前驱都未能更新,仅更新了DE之间和DG之间数据,而当F之后的E作为中间点,CD之间数据才能更新,即CD的前驱为F,为什么会如此?

    注意:这是因为F作为中间点时,CEFD中存在65535,即CF间距此时还是65535所以CD无法更新,而E作为中间点时之前更新了ED=EF+FD,所以CD=CE+ED,CD相关数据才得以更新

    结论:当MN两点之间最短路径需要经过n个顶点,那么只有当这n个中间点的相关数据全部更完,MN间的数据才能更新,也可以说,想更新MN的数据,必须保证路径上没有65535

//弗洛伊德算法:最短路径问题
public class FloydAlgorithm {
    public static void main(String[] args) {
        //测试看看图是否创建成功
        char[] vertex = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' };
        //创建邻接矩阵
        int[][] matrix = new int[vertex.length][vertex.length];
        final int N = 65535;
        matrix[0] = new int[] { 0, 5, 7, N, N, N, 2 };
        matrix[1] = new int[] { 5, 0, N, 9, N, N, 3 };
        matrix[2] = new int[] { 7, N, 0, N, 8, N, N };
        matrix[3] = new int[] { N, 9, N, 0, N, 4, N };
        matrix[4] = new int[] { N, N, 8, N, 0, 5, 4 };
        matrix[5] = new int[] { N, N, N, 4, 5, 0, 6 };
        matrix[6] = new int[] { 2, 3, N, N, 4, 6, 0 };
        Graph graph = new Graph(vertex, matrix);
        graph.floyd();
        graph.show();
    }
}

class Graph {
    private char[] vertex;
    private int[][] dis;
    private int[][] pre;

    public Graph(char[] vertex, int[][] matrix) {
        this.vertex = vertex;
        //初始化最短路径数组为邻接矩阵,直连就是最短路径,非直连则需要找
        this.dis = matrix;
        pre = new int[vertex.length][vertex.length];
        for (int i = 0; i < pre.length; i++) {
            //这里为什么如此初始化前驱节点?
            //答:因为默认开始只有两种路线:直连/不直连,两种情况下默认前驱节点都是出发点,即出发点到任何顶点的前驱节点都是自己
            //  至于后续的改动,不管最短路线改为非直连的两段还是三段,也只是针对不直连的路(即65535),
            //  而直连的两个顶点相关数据无需改动,前驱自然就是终点的前驱节点,即出发点
            Arrays.fill(pre[i], i);
        }
    }

    public void show() {
        for (int i = 0; i < vertex.length; i++) {
            for (int p : pre[i]) {
                System.out.print(vertex[p]+" ");
            }
            System.out.println();
            for (int j = 0; j < vertex.length; j++) {
                System.out.print("["+vertex[i]+"->"+vertex[j]+"="+dis[i][j]+"] ");
            }
            System.out.println("\n");
        }
    }

    public void floyd() {
        int len = 0;
        //问题:两顶点之间非直连,最短路径为3段的,最短路径是怎么更新的,如CD的最短路径为CEFD?
        //答:
        //  观察:虽然F作为中间点,但是测试时中间点第一个就用F,CD的距离和前驱都未能更新,仅更新了DE之间和DG之间数据,
        //      而当F之后的E作为中间点,CD之间数据才能更新,即CD的前驱为F,为什么会如此?
        //  注意:这是因为F作为中间点时,CEFD中存在65535,即CF间距此时还是65535所以CD无法更新,而E作为中间点时之前更新了ED=EF+FD
        //      所以CD=CE+ED,CD相关数据才得以更新
        //  结论:当MN两点之间最短路径需要经过n个顶点,那么只有当这n个中间点的相关数据全部更完,MN间的数据才能更新
        //      也可以说,想更新MN的数据,必须保证路径上没有65535
        int[] range = {5,4,3,2,1,0,6};
        for (int k : range) {
            //BC CG
            System.out.println(vertex[k] + "作为中间节点");
            for (int i = 0; i < vertex.length; i++) {
                for (int j = 0; j < vertex.length; j++) {
                    len = dis[i][k] + dis[k][j];
                    if (len < dis[i][j]) {
                        System.out.println("修改了:[" + vertex[i] + "-" + vertex[j] + "]");
                        dis[i][j] = len;
                        //直连的前驱(出发点)改为非直连后半段(最后一段)的前驱(出发点)
                        //举例:AE>AG+GE,所以A(pre[AE])=G(pre[GE])
                        pre[i][j] = pre[k][j];
                    }
                }
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/153191.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

新应用——信息化财务管理,一站式满足多个需求

财务管理应用是企业为了适应当下社会环境提出的一种将财务管理进行信息化管理的方法&#xff0c;与传统财务管理模式不同&#xff0c;将各类业务数据编制为电子数据&#xff0c;便于财务人员查找数据内容&#xff0c;可以更高效的开展工作。百数应用中心的财务管理应用涵盖了项…

机器学习笔记之深度信念网络(二)模型构建思想(RBM叠加结构)

机器学习笔记之深度信念网络——模型构建思想引言回顾&#xff1a;深度信念网络的结构表示解析RBM隐变量的先验概率通过模型学习隐变量的先验概率引言 上一节介绍了深度信念网络的模型表示&#xff0c;本节将介绍深度信念网络的模型构建思想——受限玻尔兹曼机叠加结构的基本逻…

Flutter多分支打包持续化集成

一、使用效果演示 1.1、选择参数打包 以下为参数使用说明。 packingType枚举 android、ios android ios android&ios (新功能&#xff1a;并行打包)备注&#xff1a; android、ios&#xff1a;串行打包&#xff0c;即先打一个再打一个 android&ios&#xff1a;为并行…

与香港财政司司长同台,欧科云链在这场峰会上都说了啥?

今天&#xff0c;POWER 2023香港Web3创新者峰会在中国香港如期召开&#xff0c;香港特别行政区政府财政司司长陈茂波、财经事务及库务局副局长陈浩濂、全国政协委员、立法会议员吴杰庄等港府要员出席峰会。 作为本场峰会的受邀企业&#xff0c;欧科云链控股(01499.HK)公司执行董…

Kernel Pwn基础教程之 Double Fetch

一、前言 Double Fetch是一种条件竞争类型的漏洞&#xff0c;其主要形成的原因是由于用户态与内核态之间的数据在进行交互时存在时间差&#xff0c;我们在先前的学习中有了解到内核在从用户态中获取数据时会使用函数copy_from_user&#xff0c;而如果要拷贝的数据过于复杂的话…

人工智能-正则表达式

目录1、正则表达式概述2、re模块3、匹配单个字符4、匹配多个字符5、匹配开头和结尾6、匹配分组7、总结1、正则表达式概述 在实际开发过程中经常会需要查找某些复杂字符串的格式 正则表达式&#xff1a;记录文本规则的代码 正则表达式特点&#xff1a; 语法令人头疼&#xff…

立创eda专业版学习笔记(4)(隐藏铺铜)

这里的隐藏有两个意思&#xff0c;一个是铺铜过后把铺铜的填充区域隐藏&#xff0c;方便看图&#xff0c;另外一个是隐藏铺铜的轮廓&#xff0c;方便后续改进。 第一种隐藏&#xff0c;隐藏铺铜的填充区域&#xff08;成片的图块&#xff09;&#xff0c;但是保留轮廓线 这是全…

联想LJ2655DN激光打印机清零方法

联想LJ2655DN激光打印机是市面上常见的打印机,为了节约成本,我们一般使用都是代用硒鼓来代替原装硒鼓,但是发现更换完硒鼓以后还是不能打印甚至有的机器能够打印但是打印速度会变慢或很慢,这个时候这就需要我们对打印机进行清零复位操作了,此款机器因用户更换的硒鼓类型不…

C++ 模板进阶

目录 1. 非类型模板参数 2. 模板的特化 2.1 概念 2.2 函数模板特化 2.3 类模板特化 2.3.1 全特化 2.3.2 偏特化 2.3.3 类模板特化应用示例 3. 模板总结 1. 非类型模板参数 我们在C语言中使用数组的时候可以定义静态数组&#xff0c;但是有个缺陷就是编译器在对越界检查…

Java自定义泛型类注意点

目录 自定义泛型类 如果定义了泛型类&#xff0c;实例化没有指明类的泛型&#xff0c;则认为此泛型类型为Object类型 由于子类在继承带泛型的父类时&#xff0c;指明了泛型类型。则实例化子类对象时&#xff0c;不需要指明类型 由于子类在继承带泛型的父类时&#xff0c;没有…

WebDAV之葫芦儿·派盘 + Photosync

PhotoSync 支持WebDAV方式连接葫芦儿派盘。 苹果手机通过无线传输,备份和共享照片/视频到计算机,其他手机,NAS和流行的云和照片服务的最佳解决办法,快来试下PhotoSync同步工具吧。 PhotoSync面向移动设备

安装部署wordpress(Ubuntu)

wordpress是一个目前流行的基于web的内容管理系统软件。它是基于PHP语言和MySQL数据库开发的&#xff0c;用户可以在支持 PHP 和 MySQL数据库的服务器上快速轻松的部署自己的网站&#xff08;博客&#xff0c;外贸网站等等&#xff09;。WordPress有非常多的第三方开发的免费模…

产线工控安全之现状分析及方案应对

产线安全现状 工业控制系统是支撑国民经济的重要设施&#xff0c;是工业领域的神经中枢。现在工业控制系统已经广泛应用于电力、通信、化工、交通、航天等工业领域&#xff0c;支撑起国计民生的关键基础设施。 随着传统的工业转型&#xff0c;数字化、网络化和智能化的工业控…

数学建模---数值微积分

目录 一.引言 二.数值微分 1.数值差分与差商 利用matlab观察差分与差商的区别&#xff1a; 例题&#xff1a; 二.数值积分 1.数值积分基本定理 2.常见的数值积分公式&#xff1a; 积分公式的精度&#xff1a; 3.数值积分的matlab实现 一.引言 在科学研究和工程计算中&…

LINUX提权之环境变量提权篇

前言 上一篇文章给大家介绍了linux中的内核提权的一些知识点不知道大家学的怎么样了&#xff0c;今天给大家带来一个全新的提权方法——“环境变量提权”,本文会介绍关于环境变量提权的基本知识以及利用方法。 环境变量提权 PATH是Linux系统中的环境变量&#xff0c;指定存储…

全球月活用户4年破10亿,TikTok的3大底层逻辑

武汉瑞卡迪电子商务有限公司&#xff1a;在即将过去的2022年&#xff0c;TikTok成为了众多出海品牌想要赢得新生意的重要平台。品牌应该如何看待TikTok&#xff1f;如何利用节点营销抓住机会&#xff1f;那些已经在TikTok上成功的品牌背后&#xff0c;是否有一些定式&#xff0…

centos7安装ansible

在ansible中主控机器必须是linux机器&#xff0c;不可以是windows&#xff0c;但是被控机器可以是windows。 control machine&#xff1a;192.168.184.128 target machine&#xff1a;192.168.184.129(被管理机器上不需要安装什么软件) 1.ansible的安装前提是要有python&…

vue的基础指令演示代码及简单案例

目录 一、内容绑定&#xff0c;事件绑定 v-text v-html v-on 案例&#xff1a;计数器 二、显示切换&#xff0c;属性绑定 v-show v-if v-bind 案例&#xff1a;图片切换 三、列表循环&#xff0c;表单元素绑定 v-for v-on补充 v-model 通过Vue实现常见的网页效果…

QSFP-DD封装小知识,你了解吗?

随着数据中心和高级网络应用中数据流量的上升&#xff0c;光模块市场向更高的速度&#xff0c;更低的功耗和更小的外形或尺寸发展。QSFP-DD封装有什么特征和优势&#xff1f;它与QSFP28/QSFP56模块有什么区别的&#xff1f;本期文章&#xff0c;我们一起了解一下QSFP-DD封装相关…

【Linux篇】之网络文件系统(nfs)配置

nfs : Network File System 网络文件系统 作用&#xff1a;linux内核启动之后&#xff0c;通过网络的方式从ubuntu服务器中挂载根文件系统&#xff0c; 而不需要将根文件系统部署到开发板。 1> 安装nfs服务器端 sudo apt-get install nfs-kernel-server2> 修改nfs服务的…