弗洛伊德算法(Floyd)的实现与可视化其最短路径

news2024/11/28 16:37:39

        弗洛伊德算法Floyd是针对多源路径找出最短的路径,其中数据结构会使用到前面介绍过的邻接矩阵,有兴趣的可以先查阅:图数据结构之邻接矩阵Adjacency Matrix(Python版) 先了解这个邻接矩阵然后再回看本文章也可以。

区别在于这里我们介绍的是带权值的边,通过两个步骤来思考:

1、创建邻接矩阵,和前面一样也属于对角线(值为0)对称的矩阵,区别在于我们将没有联通的点的边取值为一个比较大的值(比矩阵中的一般权值大且小于最大值避免相加溢出)即可,在很多博客也可能使用无穷大(表示永远到不了,就是没有相连的意思)来表示这个无边的情况,这点需要注意。

2、创建路径矩阵,每次插入一节点k,然后遍历每个点对(i,j双重循环),判断每个点对之间的距离会不会因为插入的点而发生最小路径(距离,权值和)的变化,如果有变小,那么就更新这两点间(i,j)的距离,所以也可以叫做插点法。

其中对于这个插入节点k,可以这么去理解,比如说从湖南到西藏,在此之前都是走A路,后面在中间修了一条路,使得湖南去西藏的路多了起来,其中经过这条新修的路,去西藏的距离变得更短了,那么我们就重新选择这条新的短路径。

了解了原理之后,我们上代码:

# 定义一个比较大的值(表示没有联通,无边)
NoEdgeV = 1000

class FloydGraph():
    '''
    弗洛伊德算法
        创建两个矩阵,一个是带权值的邻接矩阵,另一个是保存权值的路径矩阵
    nodes:节点列表
    adjacencyMatrix:保存的是点对的距离
    pathMatrix:保存路径(索引值)
    '''

    def __init__(self, nodes, adjacencyMatrix, pathMatrix):
        self.nodes = nodes
        self.ajd_matrix = adjacencyMatrix
        self.node_len = len(adjacencyMatrix)
        self.path_matrix = pathMatrix
        self._init_Floyd()

    def __call__(self, start, end):
        self.start = start
        self.end = end
        return self._format_path()

    def _init_Floyd(self):
        # 插入k点来判断路径是否需要更新
        for k in range(self.node_len):
            for i in range(self.node_len):
                for j in range(self.node_len):
                    #self.ajd_matrix[i][j] = min(self.ajd_matrix[i][j], self.ajd_matrix[i][k] + self.ajd_matrix[k][j])

                    # i到插入点k与插入点k到j的路径之和
                    tmp = self.ajd_matrix[i][k] + self.ajd_matrix[k][j]
                    # 如果插入点之后,路径变短了,那就更新这点的值即可
                    if self.ajd_matrix[i][j] > tmp:
                        self.ajd_matrix[i][j] = tmp
                        self.path_matrix[i][j] = self.path_matrix[i][k]

    def _format_path(self):
        node_list = []
        start = self.start
        end = self.end
        print("%s到%s的最短距离为:%d" % (
            self.nodes[self.start], self.nodes[self.end], self.ajd_matrix[start][end]))
        node_list.append(self.nodes[start])
        while True:
            node_list.append(self.nodes[self.path_matrix[start][end]])
            start = self.path_matrix[start][end]
            if start == end:
                break
        return node_list


def createTwoMatrix(node_map, nodes, node_list, path_map):
    for i in range(len(nodes)):
        node_map[i][i] = 0
    for n1, n2, val in node_list:
        node_map[nodes.index(n1)][nodes.index(n2)] = val
        node_map[nodes.index(n2)][nodes.index(n1)] = val
        path_map[nodes.index(n1)][nodes.index(n2)] = nodes.index(n2)
        path_map[nodes.index(n2)][nodes.index(n1)] = nodes.index(n1)

if __name__ == "__main__":
    nodes = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
    node_list = [('A', 'F', 2), ('A', 'B', 6), ('A', 'G', 5), ('A', 'C', 5),
                 ('G', 'B', 7), ('B', 'E', 3), ('C', 'B', 1), ('C', 'F', 2), ('E', 'D', 4)]

    adjMatrix = [[NoEdgeV for val in range(len(nodes))] for val in range(len(nodes))]
    pathMatrix = [[0 for val in range(len(nodes))] for val in range(len(nodes))]
    createTwoMatrix(adjMatrix, nodes, node_list, pathMatrix)

    i1 = nodes.index('A')
    i2 = nodes.index('E')
    Floydpath = FloydGraph(nodes, adjMatrix, pathMatrix)
    path = Floydpath(i1, i2)
    print(path)

'''
A到E的最短距离为:8
['A', 'F', 'C', 'B', 'E']
'''

我们来将最短路径可视化,这样看起来更直观一点。先将所有节点设置坐标,然后将获得的最短路径的节点转换成坐标,用来显示节点名称和连线用:

   #可视化
   all_xy = np.array([[3.5, 4], [5, 4], [2, 3], [4.5, 2], [6, 2], [3, 6], [4.5, 6]])
    path_index = []  # 保存节点的索引
    for i in range(len(path)):
        path_index.append(nodes.index(path[i]))
    path_xy = all_xy[path_index]  # 转成坐标

    #显示所有节点
    for i in range(len(all_xy)):
        plt.plot(all_xy[i, 0], all_xy[i, 1], color='blue',marker='$'+nodes[i]+'$', markersize=15)
    
    #突出显示最短路径节点名称
    for i in range(len(path_xy)):
        plt.plot(path_xy[i, 0], path_xy[i, 1], color='red',marker='$'+path[i]+'$', markersize=15)
    #最短路径连线
    getx = path_xy[:, 0]
    gety = path_xy[:, 1]
    plt.plot(getx, gety, color='grey', marker='.', markersize=3, linestyle='-.')
    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.title("最短路径距离:"+str(adjMatrix[i1][i2]))
    plt.show()

这块其实就是点线图的使用,全部代码如下:

import numpy as np
import matplotlib.pyplot as plt

# 定义一个比较大的值(表示没有联通,无边)
NoEdgeV = 1000


class FloydGraph():
    '''
    弗洛伊德算法
        创建两个矩阵,一个是带权值的邻接矩阵,另一个是保存权值的路径矩阵
    nodes:节点列表
    adjacencyMatrix:保存的是点对的距离,会更新成最短
    pathMatrix:保存路径(索引值)
    '''

    def __init__(self, nodes, adjacencyMatrix, pathMatrix):
        self.nodes = nodes
        self.ajd_matrix = adjacencyMatrix
        self.node_len = len(adjacencyMatrix)
        self.path_matrix = pathMatrix
        self._init_Floyd()

    def __call__(self, start, end):
        self.start = start
        self.end = end
        return self._format_path()

    def _init_Floyd(self):
        # 插入k点来判断路径是否需要更新
        for k in range(self.node_len):
            for i in range(self.node_len):
                for j in range(self.node_len):
                    #self.ajd_matrix[i][j] = min(self.ajd_matrix[i][j], self.ajd_matrix[i][k] + self.ajd_matrix[k][j])

                    # i到插入点k与插入点k到j的路径之和
                    tmp = self.ajd_matrix[i][k] + self.ajd_matrix[k][j]
                    # 如果插入点之后,路径变短了,那就更新这点的值即可
                    if self.ajd_matrix[i][j] > tmp:
                        self.ajd_matrix[i][j] = tmp
                        self.path_matrix[i][j] = self.path_matrix[i][k]

    def _format_path(self):
        node_list = []
        start = self.start
        end = self.end
        print("%s到%s的最短距离为:%d" % (
            self.nodes[self.start], self.nodes[self.end], self.ajd_matrix[start][end]))
        node_list.append(self.nodes[start])
        while True:
            node_list.append(self.nodes[self.path_matrix[start][end]])
            start = self.path_matrix[start][end]
            if start == end:
                break
        return node_list


def createTwoMatrix(node_map, nodes, node_list, path_map):
    for i in range(len(nodes)):
        node_map[i][i] = 0
    for n1, n2, val in node_list:
        node_map[nodes.index(n1)][nodes.index(n2)] = val
        node_map[nodes.index(n2)][nodes.index(n1)] = val
        path_map[nodes.index(n1)][nodes.index(n2)] = nodes.index(n2)
        path_map[nodes.index(n2)][nodes.index(n1)] = nodes.index(n1)

if __name__ == "__main__":
    nodes = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
    node_list = [('A', 'F', 2), ('A', 'B', 6), ('A', 'G', 5), ('A', 'C', 5),
                 ('G', 'B', 7), ('B', 'E', 3), ('C', 'B', 1), ('C', 'F', 2), ('E', 'D', 4)]

    adjMatrix = [[NoEdgeV for val in range(len(nodes))] for val in range(len(nodes))]
    pathMatrix = [[0 for val in range(len(nodes))] for val in range(len(nodes))]
    createTwoMatrix(adjMatrix, nodes, node_list, pathMatrix)

    i1 = nodes.index('A')
    i2 = nodes.index('E')
    Floydpath = FloydGraph(nodes, adjMatrix, pathMatrix)
    path = Floydpath(i1, i2)
    print(path)


    #可视化
    all_xy = np.array([[3.5, 4], [5, 4], [2, 3], [4.5, 2], [6, 2], [3, 6], [4.5, 6]])
    path_index = []  # 保存节点的索引
    for i in range(len(path)):
        path_index.append(nodes.index(path[i]))
    path_xy = all_xy[path_index]  # 转成坐标

    #显示所有节点
    for i in range(len(all_xy)):
        plt.plot(all_xy[i, 0], all_xy[i, 1], color='blue',marker='$'+nodes[i]+'$', markersize=15)
    
    #突出显示最短路径节点名称
    for i in range(len(path_xy)):
        plt.plot(path_xy[i, 0], path_xy[i, 1], color='red',marker='$'+path[i]+'$', markersize=15)
    #最短路径连线
    getx = path_xy[:, 0]
    gety = path_xy[:, 1]
    plt.plot(getx, gety, color='grey', marker='.', markersize=3, linestyle='-.')
    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.title("最短路径距离:"+str(adjMatrix[i1][i2]))
    plt.show()

如果说两点之间的线上面再显示出权值(两点间距离),那就更完美了,有谁知道怎么做的,欢迎留言交流。

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

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

相关文章

浅撸一下spring源码---大致内容实现

手写spring-模拟spring 1,普及一个小知识 UserService.class Component public class UserService{public void test(){ System.out.println("test") }}Test.classpublic class Test{public static void main(String[] args){AnnotationConfigApplicati…

什么软件可以将录音转写为文字?这几款好用软件不容错过

录音实时转写软件有哪些 (百)录音实时转写软件有哪些?这些录音转文字软件推荐给你 (搜)音频转文字工具有哪些?推荐三个实用转写软件 (企)哪些软件可以把录音转写为文字?这…

微信小程序|系统配送员如何登陆抢单?同城配送、预约服务

系统中有多个功能有有配送端,最主要的是同城配送,和预约服务两个功能,首先介绍一下同城配送的配送员登录(扩展的同城配送需要开启) 第一步,设置模板消息,配送员通过微信模板消息接收配送信息&am…

离婚数据可视化,经济越发达的地区离婚率越高,但为何天津离婚率最高?

这几年我国的离婚率持续走高,2021年全国各个省份平均离婚率在2.1‰,离婚率高于和低于全国平均水平的省份各有15个。 离婚率高于平均水平2.1‰有9个是北方地区,分别是天津、北京、新疆和内蒙古以及黑吉辽三省;南方地区有6个省份高…

[附源码]Python计算机毕业设计电视设备租借系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等…

最全的Go资料汇总和最走心的学Go建议

推荐语 最用心的Go学习资料和学习建议,可能没有之一。怎么学Go快?有哪些教程建议看?学到什么程度能去找工作?我觉得这个问题的关键要看你的目标是什么?一定要结合你自己的情况去考虑这个事情。 前言 最近不少读者私…

智能学习硬件小程序开发,提升学习感受

随着科学技术的飞速发展,各种智能学习硬件层出不穷,日常生活中的智能电子产品也愈来愈多,但是大部分硬件产品都是单独使用的,并没有配套的app或者小程序,在使用过程中总是会出现一些小插曲,比如&#xff1a…

FL Studio21.0.0中文版发布更新下载支持简体中文版

FL Studio 21.0.0官方中文版重磅发布纯正简体中文支持,更快捷的音频剪辑及素材管理器,多样主题随心换!Mac版新增对苹果M2/1家族芯片原生支持。 更新版本:21.0.0支持语言:简体中文/英语更新时间:2022.12.07…

[附源码]Python计算机毕业设计动物园动物饲养管理Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等…

[附源码]Python计算机毕业设计电影推荐系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等…

[附源码]Nodejs计算机毕业设计基于web的网上订餐系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置: Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术: Express框架 Node.js Vue 等等组成,B/S模式 Vscode管理前后端分…

Seekbar和ProgressBar进度条样式

有时项目中需要实现水平圆角进度&#xff0c;如下两种&#xff0c;其实很简单 下面开始看代码&#xff0c;先从主界面布局开始看起: <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/…

计算机网络:应用层

应用层 应用层是计算机体系结构中的最顶层&#xff0c;是直接为应用进程提供服务的。其作用是在实现多个系统应用进程相互通信的同时,完成一系列业务处理所需的服务. 1. C&#xff08;客户端&#xff09;/S&#xff08;服务器&#xff09;和P&#xff08;Peer&#xff09;2P&a…

Java编码实现Activemq通讯

目录 一、IDEA建Maven工程 二、pom.xml 三、JMS编码总体架构 四、粗说目的地Destination——队列和主题 五、点对点消息传递域中&#xff0c;目的地被称为队列&#xff08;queue&#xff09; 六、在发布订阅消息传递域中&#xff0c;目的地被称为主题&#xff08;topic&a…

vue axios实战,请求天气预报接口

效果预览 创建流程 1. 创建项目目录 mkdir test22. 进入目录 cd test23. 引入vue 引入vue&#xff0c; 一路敲回车就行了 npm init vuelatest4. 启动项目 创建成功&#xff0c;启动项目 cd vue-project npm install npm run dev执行run 后的访问结果 > vue-project…

简单得令人发指,说不会一定是在骗领导:配准法在地图上叠加边缘透明旅游图演示

目录 1 前言 2 基本设置 3 配准设置 4 切图 5 更简单的切图方法 1 前言 居然还有人在抱怨&#xff0c;说在地图上叠加手绘图好麻烦啊好复杂&#xff0c;都干了一星期了又要推倒重来简直不想活了&#xff0c;眼睛都累哗啦了。。。嗯&#xff0c;我相信同学你没说假话&#…

网络工程师备考5章

5.1 考点分析 5.2 WLAN基础 注&#xff1a;例如上面图中蜂窝的A&#xff0c;周围全是其他的蜂窝&#xff0c;实现了相同频率的区域隔离&#xff0c;简单了解一下它发展的几个阶段。 注&#xff1a;简单了解即可。 WLAN、802.11Wifi 这三个有什么区别&#xff1f; WLAN是无线局…

链式二叉树(C语言实现)

文章目录&#xff1a;二叉树链式结构实现1.链式二叉树的结构2.遍历二叉树2.1前序遍历2.2中序遍历2.3后序遍历2.4层序遍历3.功能接口3.1二叉树节点个数3.2叶子节点个数3.3树的深度3.4第k层节点个数&#xff08;k>1&#xff09;3.5查找目标节点3.6判断是否为完全二叉树3.7构建…

AI-多模态-2022:TCL【triple contrastive learning】【三重对比学习的视觉-语言预训练模型】

论文&#xff1a;https://arxiv.org/pdf/2202.10401.pdf 代码&#xff1a;https://github.com/uta-smile/TCL 写在前面&#xff1a; CPC[1]这篇论文中&#xff0c;作者对互信息的公式进行了分析&#xff0c;得到互信息下界的相反数为InfoNCE loss&#xff0c;即最小化InfoNC…

IPv4地址和子网掩码

目录 1.ip的定义 A.官方定义 B.IP的表现形式 C.IP地址分类 2.网络地址和主机地址 3.子网掩码 4.应用场景 1.ip的定义 A.官方定义 IP地址是一种在Internet上的给主机编址的方式&#xff0c;也称为网际协议地址。IP地址是IP协议提供的一种统一的地址格式&#xff0c;它为…