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

news2024/12/28 5:48:21

弗洛伊德算法的适用情况:弗洛伊德算法既可以用来求解有向网的最短路径长度,也可以用来求无向网的最短路径长度,但是对于图中出现负权环的情况,弗洛伊德无法的得到正确的答案

弗洛伊德的算法思想:

以此图为例讲解弗洛伊德算法的算法步骤:

 

  1. 第一步将图用邻接矩阵的数据结构存储,得到一张二维表记作ArcInfor,顶点到其自身的边权值记为0,若两个顶点之间没有直达的边则即为无穷大,如图所示:对于图的邻接矩阵的存储结构不了解的读者可以去看我的这篇博客:http://t.csdn.cn/aQaTI这篇博客里面讲了图的基本知识以及图的顺序存储方式(邻接矩阵)以及链式存储方式(邻接表)的实现过程,就是有点长可能需要一点耐心才可以看的下去
  2. 第二步,以0作为中间顶点,求每一个顶点经过顶点0到达其他顶点的路径长度,若该长度小于上表表项,则更新上表,比如以0为中间结点,求顶点2途径中间顶点0到达顶点3的路径长度为:ArcInfor[2][0[+ArcInfor[0][3]=10>ArcInfor[2][3],因此不更新此表项
  3. 第三步就是重复第二步依次将其他顶点作为中间顶点,然后求每一个顶点途径此顶点到达其它顶点的路径长度,然后符合条件就更新表项,最终得到的二维表arc中就记录了任意两对顶点之间的最短路径的长度

从以上算法思想我们已经可以得到一个大致的思路就是弗洛伊德算法只需要借助简单的三重for循环就可以实现,如

void FloydAlgorithm(int v[V],int arc[V][V],int spath[V][V])
{

	//只需要用到三重for循环即可实现弗洛伊德算法

	for (int k = 0; k < V; k++)
	{
		for (int i = 0; i < V; i++)
		{
			for (int j = 0; j < V; j++)
			{
				if (arc[i][k] + arc[k][j] < arc[i][j])
				{
					arc[i][j] = arc[i][k] + arc[k][j];
					spath[i][j] = k;
				}

			}
		}
	}
	//打印最短路径
	print_spath(v, arc, spath);

}


 最外层循环控制变量是用于实现步骤“依次将每一个顶点作为中间顶点“,而内层的两层循环是用于实现”以某个顶点作为中间节点时,每一个顶点经过此结点到达其它顶点的最短路径“;

对于这题,我们不禁想要得到一个简单的最短路径长度,我们还期望得到任意两个顶点之间的最短路径,即将路径上途径的顶点输出;这里我们需要借助一个二维矩阵spath来实现,spath[i][j]的含义是,顶点i与j之间的中间顶点;输出对最短路径的代码如下,对于输出最短路径的代码,读者可能不是很清楚,这时候可以把我的代码调试一遍,观察各个变量取值的变化情况,这样你就能理解算法的设计思路了,对于我来说,我每次看不太懂别人的代码的时候用的都是此方法

//以下函数用于输出两个顶点之间的最短路径间需要经过那些顶点,不包括源节点和目的节点
void output(int v[V],int spath[V][V],int start,int end)         //start,end表示的是顶点所在的数组中的下标。
{
	//该函数需要用到递归思想,我们从右往左输出源节点到目的节点所经过的顶点的信息
	int k = spath[start][end];         //即从start到end中间需要经过的一个顶点再顶点数组中的下标

	if (k == -1)
	{
		return;
	}
	output(v, spath, start, k);
	printf("%d->", v[k]);
	output(v, spath, k, end);
}

//以下函数用于打印图中任意两个结点之间的最短路径
void print_spath(int v[V],int arc[V][V],int spath[V][V])
{
	for (int i = 0; i < V; i++)
	{
		for (int j = 0; j < V; j++)
		{
			if (i == j)
			{
				continue;
			}
			else
			{
				if (arc[i][j] >= INF)
				{
					printf("%d->%d之间不存在路径\n", v[i], v[j]);
				}
				else
				{
					printf("%d->%d之间的最短路径长度为:%d\n", v[i],v[j],arc[i][j]);
					printf("%d->%d之间的最短路径为:\n", v[i], v[j]);
					printf("%d->", v[i]);
					output(v, spath, i, j);
					printf("%d\n", v[j]);
				}
			}

		}
	}
}

完整程序源代码以及运行结果截图:

程序源代码:


//用弗洛伊德算法求图的最短路径

//弗洛伊德算法既可以用来求无向图的最短路径,也可以用来求有向图的最短路径;

//注意:弗洛伊德算法不可以用于求存在负权环的图的最短路径

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>


#define V 4     //顶点的数目 
#define INF 60000         //用于定义一个大数,当两个顶点之间不存在边或者弧时,在邻接矩阵中的对应位置上填上该大数,infinity:无穷大



//采用邻接矩阵的方式来存储图的边的信息



//以下函数用于输入图的边的顶点信息和边的信息
void input(int *v,int arc[V][V]);


//以下函数用于实现弗洛伊德算法

void FloydAlgorithm(int v[V], int arc[V][V], int spath[V][V]);


//以下函数用于输出两个顶点之间的最短路径间需要经过那些顶点,不包括源节点和目的节点
void output(int v[V], int spath[V][V], int start, int end);

//以下函数用于打印图中任意两个结点之间的最短路径
void print_spath(int v[V], int arc[V][V], int spath[V][V]);

int main()
{
	int vertex[V];         //用于存放图的顶点信息
	int ArcInfor[V][V];          //用于存放图的边的信息
	int spath[V][V];            //用于记录两个顶点之间的最短路径
	for (int i = 0; i < V; i++)
	{
		for (int j = 0; j < V; j++)
		{
			spath[i][j] = -1;
		}
	}
	//输入图的弧的信息和边的信息
	input(vertex, ArcInfor);

	//求最短路径
	FloydAlgorithm(vertex, ArcInfor, spath);

	return 0;


}


void input(int* v, int arc[V][V])
{
	printf("请输入图的顶点信息:\n");
	for (int i = 0; i < V; i++)
	{
		scanf("%d", &v[i]);
	}


	printf("请输入图的边的信息:\n");
	for (int i = 0; i < V; i++)
	{
		for (int j = 0; j < V; j++)
		{
			scanf("%d", &arc[i][j]);
			
		}
	}
	
}

//以下函数用于输出两个顶点之间的最短路径间需要经过那些顶点,不包括源节点和目的节点
void output(int v[V],int spath[V][V],int start,int end)         //start,end表示的是顶点所在的数组中的下标。
{
	//该函数需要用到递归思想,我们从右往左输出源节点到目的节点所经过的顶点的信息
	int k = spath[start][end];         //即从start到end中间需要经过的一个顶点再顶点数组中的下标

	if (k == -1)
	{
		return;
	}
	output(v, spath, start, k);
	printf("%d->", v[k]);
	output(v, spath, k, end);
}

//以下函数用于打印图中任意两个结点之间的最短路径
void print_spath(int v[V],int arc[V][V],int spath[V][V])
{
	for (int i = 0; i < V; i++)
	{
		for (int j = 0; j < V; j++)
		{
			if (i == j)
			{
				continue;
			}
			else
			{
				if (arc[i][j] >= INF)
				{
					printf("%d->%d之间不存在路径\n", v[i], v[j]);
				}
				else
				{
					printf("%d->%d之间的最短路径长度为:%d\n", v[i],v[j],arc[i][j]);
					printf("%d->%d之间的最短路径为:\n", v[i], v[j]);
					printf("%d->", v[i]);
					output(v, spath, i, j);
					printf("%d\n", v[j]);
				}
			}

		}
	}
}



void FloydAlgorithm(int v[V],int arc[V][V],int spath[V][V])
{

	//只需要用到三重for循环即可实现弗洛伊德算法

	for (int k = 0; k < V; k++)
	{
		for (int i = 0; i < V; i++)
		{
			for (int j = 0; j < V; j++)
			{
				if (arc[i][k] + arc[k][j] < arc[i][j])
				{
					arc[i][j] = arc[i][k] + arc[k][j];
					spath[i][j] = k;
				}

			}
		}
	}
	//打印最短路径
	print_spath(v, arc, spath);

}


 运行结果截图:

祝学习进步,生活愉快! 

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

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

相关文章

C语言杂七杂八

fget函数的用法 fgets() 函数用来从指定的文件中读取一个字符串&#xff0c;并保存到字符数组中。 str 为字符数组&#xff0c;n 为要读取的字符数目&#xff0c;fp 为文件指针。 char *fgets(char *str, int n, FILE *stream) 返回值&#xff1a;读取成功时返回字符数组首地…

python图像处理实战(一)—图像基础

&#x1f680;写在前面&#x1f680; &#x1f58a;个人主页&#xff1a;https://blog.csdn.net/m0_52051577?typeblog &#x1f381;欢迎各位大佬支持点赞收藏&#xff0c;三连必回&#xff01;&#xff01; &#x1f508;本人新开系列专栏—python图像处理 ❀愿每一个骤雨初…

Android12之service调试(一百五十二)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

C4D R26 渲染学习笔记 建模篇(3):生成器

文章目录 前文回顾介绍篇建模篇 生成器介绍生成器变形器搭配举例 生成器详细介绍细分曲面布料曲面 未完待续 前文回顾 介绍篇 C4D R26 渲染学习笔记&#xff08;1&#xff09;&#xff1a;C4D版本选择和初始UI框介绍 C4D R26 渲染学习笔记&#xff08;2&#xff09;&#xff…

微服务Spring Cloud 02------使用Eureka实现注册中心(1)

1.Eureka简介 Eureka是Spring Cloud中的一个负责服务注册与发现的组件。遵循着CAP理论中的A(可用性)和P(分区容错性)。 Eureka是Netflix中的一个开源框架。它和 Zookeeper、Consul一样&#xff0c;都是用于服务注册管理的&#xff0c;同样&#xff0c;Spring-Cloud 还集成了Zo…

Canvas画布基本功能及实现网页签名功能

canvas 简介 <canvas> 是 HTML5 新增的&#xff0c;一个可以使用脚本(通常为 JavaScript) 在其中绘制图像的 HTML 元素。它可以用来制作照片集或者制作简单(也不是那么简单)的动画&#xff0c;甚至可以进行实时视频处理和渲染。和所有 DOM 元素一样&#xff0c;拥有自己…

chatgpt赋能python:Python中累乘的作用和用法

Python中累乘的作用和用法 在Python编程语言中&#xff0c;累乘指的是连续乘法&#xff0c;或者说是一系列数字的乘积。累乘的概念非常简单&#xff0c;但是实际上它在编程中有着广泛的应用。 累乘在Python中的实现方式 Python中&#xff0c;累乘可以通过多种方式来实现&…

手写一个webpack插件(plugin)

熟悉 vue 和 react 的小伙伴们都知道&#xff0c;在执行过程中会有各种生命周期钩子&#xff0c;其实webpack也不例外&#xff0c;在使用webpack的时候&#xff0c;我们有时候需要在 webpack 构建流程中引入自定义的行为&#xff0c;这个时候就可以在 hooks 钩子中添加自己的方…

使用docker和minio实现对象存储

文章目录 使用docker和minio实现对象存储什么是minio安装minio使用minio 使用docker和minio实现对象存储 什么是minio ​ Minio是一个开源的分布式文件存储系统&#xff0c;它基于 Golang 编写,虽然轻量&#xff0c;却拥有着不错的高性能&#xff0c;可以将图片、视频、音乐、…

Sequelize:Node.js 中的强大 ORM 框架

❤️砥砺前行&#xff0c;不负余光&#xff0c;永远在路上❤️ 目录 前言优势&#xff1a;提高效率&#xff0c;不用SQL即可完成数据库操作。 那什么是 Sequelize&#xff1f;主要特性&#xff1a;1、模型定义和映射&#xff1a;2、关联和联接&#xff1a;3、事务管理&#xff…

Java性能权威指南-总结2

Java性能权威指南-总结2 性能测试方法原则2:理解批处理流逝时间、吞吐量和响应时间批处理流逝时间吞吐量测试 原则3:用统计方法应对性能的变化 性能测试方法 原则2:理解批处理流逝时间、吞吐量和响应时间 性能测试的第2条原则是多角度审视应用性能。应该测量哪个指标取决于对…

chatgpt赋能python:Python中的与非

Python中的与非 在Python编程中&#xff0c;我们经常会用到与非运算符&#xff0c;用来判断条件语句中的真假性。在本文中&#xff0c;我们将介绍Python中的与非运算符&#xff0c;并探讨其用法和实际应用场景。 什么是与非运算符&#xff1f; 与非运算符是一个布尔操作符&a…

NeRF-SLAM代码记录

前言 没运行成功,尤其是编译gtsam部分,每一步都有错,又是讨厌c++第一天。 这一行编译到92% 就会报错 python/CMakeFiles/gtsam_py.dir/build.make:250: recipe for target python/CMakeFiles/gtsam_py.dir/linear.cpp.o failed make[2

.NET 8 Preview 4 发布

作者&#xff1a;Jon Douglas - Principal Program Manager, NuGet 翻译&#xff1a;Alan Wang 排版&#xff1a;Alan Wang 我们很高兴与大家分享在 .NET 8 预览版 4 中的所有新功能和改进&#xff01;这次发布是继预览版 3之后的更新。您将在这些月度发布中看到更多功能逐渐亮…

【无标题】win11打开VMware虚拟机蓝屏解决

win11打开VMware虚拟机蓝屏解决 win11打开虚拟机蓝屏&#xff01;&#xff01;&#xff01;解决方案&#xff1a;win11支持16.2以上版本&#xff0c;其他版本不兼容&#xff0c;可用文末的卸载工具卸载之前已安装版本&#xff08;深度卸载&#xff09;&#xff0c;然后下载16.2…

chatgpt赋能python:Python中的乘号:一个重要的数学运算符

Python中的乘号&#xff1a;一个重要的数学运算符 在 Python 编程语言中&#xff0c;乘号通常是使用“*”表示的数学运算符。这个运算符非常常用&#xff0c;它可以在各种情况下使用。本文将探讨 Python 中乘号的基本用法&#xff0c;以及更高级的用法。 基本用法 在 Python…

python+django高校人事管理系统vue

本高校人事管理系统以Django作为框架&#xff0c;Python语言&#xff0c;B/S模式以及MySql作为后台运行的数据库。本系统主要包括以下功能模块&#xff1a;用户、院长、职称申报、工资信息、绩效信息、奖惩信息、招聘、科系分类等模块。 本文着重阐述了高校人事管理系统的分析、…

easyX实践上手操作小项目

easyX实践上手操作小项目 效果展示主菜单的装饰玩法介绍界面开始游戏界面制作团队界面排行榜界面注&#xff1a;main()函数拓展数据库小结 这里我们学习过easyX的基础知识后&#xff0c;看看是否能实践操作一下&#xff0c;制作一个属于自己的游戏界面呢&#xff1f; 基础知识…

基于深度学习的高精度野生目标检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于深度学习的高精度野生目标检测识别系统可用于日常生活中检测与定位野生目标目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的野生目标目标检测识别&#xff0c;另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标检测…

开源SCRM营销平台MarketGo-账号管理

一、概述 企业在经营的过程中&#xff0c;因为业务、税收等各种因素的需要在各地成立分公司&#xff0c;这样针对公司来说管理成本&#xff0c;运营成本&#xff0c;营销成本都会提高&#xff0c;并且沟通的效率也会变低。 在用户营销的场景中&#xff0c;MarketGo在SCRM做了…