Floyd 算法研究(P 矩阵详解)

news2024/11/15 12:45:19

Floyd 算法研究

理论基础

求最短路径Floyd算法!

Floyed(floyd)算法详解

Floyd-傻子也能看懂的弗洛伊德算法

最短路径Floyd算法【图文详解】

最短路径问题—Floyd算法详解

算法:最短路径之弗洛伊德(Floyd)算法

弗洛伊德(Floyd)算法求图的最短路径

《基于优化Floyd算法的室内机器人路径规划研究》

建议先看第一个 B 站视频和第三篇博客,能够对 Floyd 算法有快速的了解和认识

Floyd算法又称为插点法,是一种用于寻找给定的加权图中多源点之间最短路径的算法。Floyd算法适用于解决任意两点间的最短路径的一种算法,同时也被用于计算有向图的传递闭包。此算法简单有效,而且由于其三重循环结构紧凑,对于稠密图,规划效率要高于Dijkstra算法

Floyd算法主要用来求多源、无负权边的最短路径,Floyd算法是一个经典的动态规划算法

从任意节点i到任意节点j的最短路径不外乎2种可能,一是直接从ij,二是从i经过若干个节点kj

我们假设Dis(i,j)为节点u到节点v的最短路径的距离,对于每一个节点k,我们检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,证明从ik再到j的路径比i直接到j的路径短,我们便设置Dis(i,j) = Dis(i,k) + Dis(k,j),这样一来,当我们遍历完所有节点kDis(i,j)中记录的便是i到j的最短路径的距离

在这里插入图片描述

算法描述:

  1. 从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大
  2. 对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比己知的路径更短。如果是则更新它

Floyd算法使用两个矩阵来进行最短路径的计算

  • 首先,定义一个n×n的矩阵D,其中n是图中顶点的数量。矩阵D的元素D[i][j]表示顶点i到顶点j的最短路径的权值。初始时,矩阵D的元素被初始化为图中边的权值
  • 然后,定义一个n×n的矩阵P,用于记录最短路径的前驱顶点。矩阵P的元素P[i][j]表示顶点i到顶点j的最短路径中,顶点j前驱顶点的编号。初始时,矩阵P的元素被初始化为顶点i到顶点j之间存在边时的前驱顶点编号
  • 接下来,通过两层循环迭代计算矩阵D和P。在每一次迭代中,将顶点k作为中间节点,更新矩阵DP的元素,以找到更短的路径。具体的更新规则是通过比较矩阵D[i][k] + D[k][j]与当前矩阵D[i][j]的大小来确定是否更新路径和更新前驱顶点
  • 最后,完成所有迭代后,矩阵D中的元素即为每对顶点之间的最短路径的权值,矩阵P中的元素可以用于还原最短路径

在这里插入图片描述

上图中的 P 矩阵有误,D 矩阵很好理解,关键是 P 矩阵, 主要涉及到 3 个问题

  • P 矩阵如何初始化
  • P 矩阵在循环中如何更新
  • 如何通过 P 矩阵还原两点间最短路径

P 矩阵初始化

在使用Floyd算法之前,可以通过初始化矩阵P来为每对顶点之间的最短路径记录前驱节点

  1. 如果存在从节点 i 到节点 j 的边,则可以初始化P[i][j]为i表示节点 i 是节点 j 的前驱节点,直接从节点 i 到节点 j 的路径是最短路径的一部分
  2. 如果不存在从节点 i 到节点 j 的边,则可以初始化P[i][j]为-1,表示节点i到节点 j 之间没有路径

下面是一个示例代码,展示如何初始化矩阵P:

#include <iostream>
#include <vector>

void initializeP(std::vector<std::vector<int>>& P, const std::vector<std::vector<int>>& graph, int numVertices) {
    for (int i = 0; i < numVertices; ++i) {
        for (int j = 0; j < numVertices; ++j) {
            if (graph[i][j] != INF && i != j) {
                P[i][j] = i;
            } else {
                P[i][j] = -1;
            }
        }
    }
}

int main() {
    int numVertices = 4;
    std::vector<std::vector<int>> graph = {{0, 3, 8, INF},
                                           {INF, 0, INF, 1},
                                           {INF, 4, 0, INF},
                                           {2, INF, -5, 0}};

    std::vector<std::vector<int>> P(numVertices, std::vector<int>(numVertices));

    // Initialize P matrix
    initializeP(P, graph, numVertices);

    // Print the initialized P matrix
    for (int i = 0; i < numVertices; ++i) {
        for (int j = 0; j < numVertices; ++j) {
            std::cout << P[i][j] << " ";
        }
        std::cout << std::endl;
    }

    return 0;
}

P 矩阵在循环中更新

在Floyd算法中,矩阵P用于记录最短路径上的前驱顶点。下面是Floyd算法中P矩阵的更新规则:

  1. 初始化矩阵P:假设有一个图G,其中顶点的编号从1到 n。初始时,矩阵P的元素P[i][j]等于i,表示从顶点 i 到顶点 j 的最短路径上,顶点 j 的前驱顶点是顶点 i
  2. 迭代更新P矩阵:Floyd算法通过逐步迭代更新矩阵P和最短路径矩阵D。在每一轮迭代中,检查顶点k是否可以作为顶点i到顶点j最短路径的中间顶点。如果可以,即存在更短的路径,更新矩阵P中对应的元素P[i][j]为 k

具体的更新规则如下:

for k = 1 to n do
    for i = 1 to n do
        for j = 1 to n do
            if (D[i][j] > D[i][k] + D[k][j]) then
                D[i][j] = D[i][k] + D[k][j]
                P[i][j] = P[k][j]

其中,D矩阵表示顶点之间的最短路径长度。如果在第 k 轮迭代中发现从顶点 i 到顶点 j 的路径经过顶点 k 时更短,那么更新D[i][j]为更小的路径长度,并且更新P[i][j]为顶点 k,表示顶点 j 的前驱顶点是顶点 k

通过这样的迭代更新,最终可以得到最短路径矩阵D前驱矩阵P

由 P 矩阵还原最短路径

Floyd算法中使用矩阵P来记录最短路径的前驱节点。通过P矩阵可以还原最短路径。下面是还原最短路径的步骤:

  1. 首先,如果P[i][j] == -1,则表示从节点i到节点j不存在路径,即没有最短路径可还原
  2. 如果P[i][j] == i,表示节点 j前驱节点就是 i,即直接从节点 i 到节点 j 的路径为最短路径的一部分
  3. 如果P[i][j] ≠ i,则表示节点 j 的前驱节点是P[i][j]。需要递归地从节点 j 到节点 P[i][j] 还原路径,并输出节点 j,即先还原前面的节点,再输出节点 j

D矩阵非常容易理解。难点在于P矩阵,不好定义,从而产生误解。其实P矩阵可以理解为记录顶点间最短路径的目标点的前置跳转点,它并不是直接可以得出最短路径。也就是说P矩阵里的一个值并不能得出最短路径,而是需要不断的迭代,将上一步的前置跳转点作为这一步的目标点,继续查找当前目标点的前置跳转点,这样进行下来,直到查到起点结束。这样才能得出真正的最短路径

Talk is always cheap. 以第三篇博客中的内容作为示例,编写测试代码

在这里插入图片描述

#include <vector>
#include <iostream>
using namespace std;

template<typename T>
void printArr(vector<T> arr)
{
	for (T val : arr)
	{
		cout << val << "\t";
	}
	cout << endl;
}

template<typename T>
void printTwoDimensationArr(vector<vector<T>> arr)
{
	int n = arr.size();
	for (int i = 0; i < n; ++i)
	{
		printArr<T>(arr[i]);
	}
	cout << endl;
}

#define INF 99999

void restorePath(int i, int j, const vector<vector<int>>& P) {
	if (i == j) {
		cout << i << "  ";
	}
	else if (P[i][j] == -1) {
		cout << "No path exists";
	}
	else {
		restorePath(i, P[i][j], P);
		cout << j << "  ";
	}
}

void floydAlgorithm(vector<vector<int>>& graph, int numVertices) {
	vector<vector<int>> dist(numVertices, vector<int>(numVertices));
	vector<vector<int>> P(numVertices, vector<int>(numVertices));

	// Initialize dist and P matrices
	for (int i = 0; i < numVertices; ++i) {
		for (int j = 0; j < numVertices; ++j) {
			dist[i][j] = graph[i][j];
			if (i == j || graph[i][j] == INF) {
				P[i][j] = -1;
			}
			else {
				P[i][j] = i;
			}
		}
	}

	// Floyd algorithm
	cout << "Distance Array:" << endl;
	printTwoDimensationArr<int>(dist);
	cout << "Path Array:" << endl;
	printTwoDimensationArr<int>(P);
	for (int k = 0; k < numVertices; ++k) {
		for (int i = 0; i < numVertices; ++i) {
			for (int j = 0; j < numVertices; ++j) {
				if (dist[i][j] > dist[i][k] + dist[k][j]) {
					dist[i][j] = dist[i][k] + dist[k][j];
					P[i][j] = P[k][j];
				}
			}
		}
		cout << "Distance Array:" << endl;
		printTwoDimensationArr<int>(dist);
		cout << "Path Array:" << endl;
		printTwoDimensationArr<int>(P);
	}

	// Print shortest paths
	for (int i = 0; i < numVertices; ++i) {
		for (int j = 0; j < numVertices; ++j) {
			if (i != j) {
				cout << "Shortest path from " << i << " to " << j << ": ";
				restorePath(i, j, P);
				cout << endl;
			}
		}
	}
}

int main() {
	int numVertices = 4;
	vector<vector<int>> graph = { {0, 2, 6, 4},
								  {INF, 0, 3, INF},
								  {7, INF, 0, 1},
								  {5, INF, 12, 0} };

	floydAlgorithm(graph, numVertices);

	return 0;
}

在上述示例代码中,graph表示图的邻接矩阵,其中INF表示两个顶点之间不存在直接边的情况。numVertices表示顶点的数量。程序通过Floyd算法计算最短路径,并使用restorePath函数通过 P 矩阵还原最短路径

输出如下

Distance Array:
0       2       6       4
99999   0       3       99999
7       99999   0       1
5       99999   12      0

Path Array:
-1      0       0       0
-1      -1      1       -1
2       -1      -1      2
3       -1      3       -1

Distance Array:
0       2       6       4
99999   0       3       99999
7       9       0       1
5       7       11      0

Path Array:
-1      0       0       0
-1      -1      1       -1
2       0       -1      2
3       0       0       -1

Distance Array:
0       2       5       4
99999   0       3       99999
7       9       0       1
5       7       10      0

Path Array:
-1      0       1       0
-1      -1      1       -1
2       0       -1      2
3       0       1       -1

Distance Array:
0       2       5       4
10      0       3       4
7       9       0       1
5       7       10      0

Path Array:
-1      0       1       0
2       -1      1       2
2       0       -1      2
3       0       1       -1

Distance Array:
0       2       5       4
9       0       3       4
6       8       0       1
5       7       10      0

Path Array:
-1      0       1       0
3       -1      1       2
3       0       -1      2
3       0       1       -1

Shortest path from 0 to 1: 0  1
Shortest path from 0 to 2: 0  1  2
Shortest path from 0 to 3: 0  3
Shortest path from 1 to 0: 1  2  3  0
Shortest path from 1 to 2: 1  2
Shortest path from 1 to 3: 1  2  3
Shortest path from 2 to 0: 2  3  0
Shortest path from 2 to 1: 2  3  0  1
Shortest path from 2 to 3: 2  3
Shortest path from 3 to 0: 3  0
Shortest path from 3 to 1: 3  0  1
Shortest path from 3 to 2: 3  0  1  2

手推了一遍 D 矩阵和 P 矩阵的更新过程,P 矩阵的初始化有些小瑕疵,有些位置没有初始化为 -1

右侧简单模拟了由 1 号节点到 0 号节点通过递归还原路径的过程

在这里插入图片描述

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

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

相关文章

DS18B20数字温度传感器的工作原理引脚及功能实物读取温度原理图

DS18B20温度传感器仿真图 . . . . 功能描述&#xff1a; 1 本实验采用DS18B20作为温度检测模块&#xff0c;51单片机&#xff0c;液晶1602显示&#xff0c;报警电路&#xff0c;按键电路。 2 液晶上面T代表温度&#xff0c;H代表上限值&#xff0c;L代表下限值 3 这个上下限值…

阿里云安全提醒:网站涉及违法不良信息该怎么办

北京某客户的网站突然收到阿里云的短信告警说&#xff0c;【阿里云】尊敬的********qq.com:您网站www.*******.com涉及违法不良信息&#xff0c;请尽快核查清理&#xff0c;详见站内信及邮件。客户有点懵&#xff0c;不知道为何会收到这样的一条短信&#xff0c;但阿里云也不会…

LTV-61L-ASEMI代理台湾光宝高速光耦LTV-61L

编辑&#xff1a;ll LTV-61L-ASEMI代理台湾光宝高速光耦LTV-61L 型号&#xff1a;LTV-61L 品牌&#xff1a;台湾光宝 封装&#xff1a;LSOP-6 引脚数量&#xff1a;6 类型&#xff1a;光耦 特性&#xff1a;台湾光宝、IGBT驱动器、储能专用光耦&#xff3c;高速光耦 封…

怎么一键远程访问无人值守电脑?

远程办公和无人值守的远程访问 如今&#xff0c;远程办公越来越人们所熟知。远程办公需要在没有其他人帮助的情况下访问您的办公室计算机并接受远程请求。那么如何从外面完成对办公室电脑的无人值守远程访问呢&#xff1f; 众所周知&#xff0c;远程桌面使您能够通过…

基于SpringBoot的点餐系统的设计与实现(源码+数据库+文档+说明)

系统主要采用了 Spring Boot、 Mybatis的框架&#xff0c; MySQL作为开发数据库&#xff0c;利用 MVC的设计理念&#xff0c;实现了管理端管理员工及菜品信息发布、员工账号菜品信息发布及配送、移动端查看菜品信息及消费等基本的功能需求。 关键技术介绍 操作系统&#xff1…

【Visual modflow Flex】地下水数值模拟及参数优化、抽水实验设计与处理、复杂的饱和/非饱和地下水流分析实践技术

本次地下水数值模拟软件的应用&#xff0c;主要围绕目前应用较为广泛的Visual Modflow Flex 系列版本开展&#xff0c;结合具体应用场景&#xff0c;实例讲解软件的全流程应用过程&#xff0c;包括数据处理分析、数值模型构建以及模拟结果的输出等。通过建模篇、优化篇、真实案…

Evoto AI 图像编辑软件 - 女性人像选项(英中对照)

Female 女性 Blemish Removal 瑕疵修复 Freckle & Acne 雀斑与痘痘 Face Mole 面部痣 Body Blemish 身体瑕疵 Fixing Oily Face 修复油脸 Face Forehead Wrinkle 面部额头皱纹 Eye Wrinkle 眼部皱纹 Dark Circle 黑眼圈 Smile Line 笑纹&#xff0c;法令纹 Neck Wrinkle 颈…

【从零开始学习JAVA | 第二十篇】常见API介绍 Math

目录 前言&#xff1a; MATH: Math类中的常用方法&#xff1a; 总结&#xff1a; 前言&#xff1a; 本篇往后我们会详细介绍一些常用的API&#xff0c;今天我们介绍的是Math的常用方法。但是其实我们不需要记住所有的方法&#xff0c;在日常工作中自己学会查询API文档就可以…

Docker 安装 Mysql 数据库

一、官方推荐安装方式&#xff1a; 1、执行 docker pull mysql:5.6 命令&#xff0c;下载 mysql 镜像&#xff0c;如下所示&#xff1a; 2、执行命令&#xff0c;创建并启动 mysql 容器 docker run -d --name mysql5.6-3306 -p 3307:3306 -e MYSQL_ROOT_PASSWORD123456 mysq…

Linux tracing之内核vsyscallvdso机制分析

由于内核运行在受保护的地质空间上&#xff0c;Linux系统中的用户空间程序无法直接执行内核代码&#xff0c;不能直接调用内核空间中的函数&#xff0c;因此&#xff0c;应用程序以某种方式通知系统&#xff0c;告诉内核自己需要执行一function&#xff0c;希望系统系统切换到内…

亚马逊、沃尔玛测评防关联、防封号环境的底层技术原理

大家好我是亚马逊测评珑哥&#xff0c;今天我给大家讲一下做亚马逊、沃尔玛测评、采购、退款需要用到的防关联、防封号环境的一些底层技术原理。这里讲的内容我相信很少有人能掌握&#xff0c;都是一些比较难的IT术技。 近期很多做测评、采购、退款、撸卡、撸货的朋友加我&…

小程序代码审核新手入门篇

微信小程序在注册完成&#xff0c;需提交代码审核通过才能顺利发布&#xff0c;小程序从开发到发布的具体流程&#xff1a;微信小程序完成注册、信息设置、类目设置后&#xff0c;代码提审从开发到发布一般要经过&#xff1a;预览-> 上传代码 -> 提交审核 -> 发布等步…

vue axios 同步请求

创建目录scr/api/http2 创建scr/api/http2/ndex.js import axios from axiosconst url "http://xxx.com:9000/"; let data export default {apipost(uri, params) {var that this return new Promise((resolve, reject) > {axios.post(urluri, {appkey:sssa,…

NXP i.MX 8M Mini工业核心板硬件说明书(四核ARM Cortex-A53 + 单核ARM Cortex-M4,主频1.6GHz)

1 硬件资源 创龙科技SOM-TLIMX8是一款基于NXP i.MX 8M Mini的四核ARM Cortex-A53 单核ARM Cortex-M4异构多核处理器设计的高端工业级核心板&#xff0c;ARM Cortex-A53(64-bit)主处理单元主频高达1.6GHz&#xff0c;ARM Cortex-M4实时处理单元主频高达400MHz。处理器…

vim行号背景配置

没有修改前&#xff0c;在vim里面显示行号是这样的&#xff0c;背景颜色是灰色的。 在文件~/.vim/colors/bandit.vim中使用hi命令清除行号的背景. 即打开291行的注释后&#xff0c;:wq保存后&#xff0c;立刻可以看到背景颜色已经去除。

Hadoop_Yarn实践 (三) => (Yarn的基础架构、原理、容量/公平调度器、Tool接口、Yarn常用命令、核心参数)

目录 Hadoop_HDFS、Hadoop_MapReduce、Hadoop_Yarn 实践 (三)一、Hadoop_HDFS二、Hadoop_MapReduce三、Hadoop_Yarn1、Yarn资源调度1.1、基础架构1.2、Yarn的工作调度机制&#xff08;Job提交过程&#xff09;1.3、Yarn 调度器和调度算法1.3.1、先进先出调度器&#xff08;FIFO…

【Visual Studio】报错 ASSERT: “i >= 0 i < size()“,使用 C++ 语言,配合 Qt 开发串口通信界面

知识不是单独的&#xff0c;一定是成体系的。更多我的个人总结和相关经验可查阅这个专栏&#xff1a;Visual Studio。 这个 Bug 是我做这个工程时遇到的&#xff1a;【Visual Studio】Qt 的实时绘图曲线功能&#xff0c;使用 C 语言&#xff0c;配合 Qt 开发串口通信界面。 文…

Python学习——字典

一、字典的定义 &#xff08;1&#xff09;字典也是Python内置的数据结构之一&#xff0c;和列表一样都是可变序列&#xff0c;也就是说字典也能够进行增、删、改的操作。字典是以键值对的方式存储数据的&#xff0c;所以在字典中包含键和值。不同于数组&#xff0c;字典是一个…

manjaro 设置 vscode 为默认编辑器

manjaro 现在的默认编辑器是kate 换成vscode xdg-mime default code.desktop text/plain Setting VS Code as the default text editor

接口调用参数篡改测试-业务安全测试实操(22)

接口调用参数篡改测试,接口未授权访问/调用测试 接口调用参数篡改测试 测试原理和方法 在短信、邮件调用业务环节中,例如短信验证码、邮件验证码。修改对应请求中手机号或邮箱地址参数值提交后,如果修改后的手机号或邮箱收到系统发送的信息,则表示接口数据调用参数可篡改 …