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

news/2024/11/8 1:40:48/

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

弗洛伊德的算法思想:

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

 

  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.ppmy.cn/news/110055.html

相关文章

Asp.netERP客户关系系统设计(源代码+论文)

ERP(Enterprise Resources Planning,企业资源计划),是指建立在信息技术应用基础上,结合系统化的管理思想,为企业决策层及员工提供决策手段的管理平台。 车间管理子系统要求根据物料需求计划,能力需求计划以及生产工艺流程制定车间作业计划,车间管理人员按车间作业计划…

学成在线项目Docker配置笔记

mybatis docker run \ -p 3306:3306 \ --name mysql \ -v ~/mysql/data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORDroot \ --privilegedtrue \ docker.io/mysql gogs docker run \ --namegogs \ -p 122:22 \ -p 3001:3000 \ -v /var/gogs:/data gogs/gogs xuxueli/xxl-job(第一个…

Python读写mat文件(使用scipy.io)

在matlab中&#xff0c;数据可保存为mat文件&#xff0c;使用save和load命令可进行读写操作。而在Python中&#xff0c;也可以对mat文件进行读写。 一、由matlab向Python传数据&#xff08;Python读取mat文件&#xff09; 第一步&#xff1a;使用matlab创建变量并保存至mat文…

网络无法分配 IP 地址有什么原因?

IP地址是计算机网络中用于唯一标识一台设备的地址&#xff0c;由四部分组成&#xff1a; 网络地址&#xff1a;表示设备所连接的网络的地址&#xff0c;多数情况下是点分十进制表示的。 主机地址&#xff1a;表示设备在网络中的具体物理地址&#xff0c;也是点分十进制表示的。…

黑马Redis视频教程实战篇(一)

目录 一、短信登录 1.1、导入黑马点评项目 &#xff08;1&#xff09;导入黑马点评sql脚本 &#xff08;2&#xff09;导入后端项目 &#xff08;3&#xff09;导入前端项目 1.2、基于Session实现登录流程 1.3 、实现发送短信验证码功能 1.4 、实现登录拦截功能 1.5 、隐…

Linux系统下imx6ull QT编程—— Ubuntu 下编写程序(一)

Linux QT编程 文章目录 Linux QT编程前言一、C简介二、C环境设置1.安装编译 C 语言和 C的环境。2.创建文件编写代码3.编译运行代码 总结 前言 绍在 Ubuntu 在终端窗口下使用 vi/vim 编辑一个 C源文件。通过编写最简单的示例“Hello,World QCX”。 一、C简介 C &#xff08;c…

使用Intel ARC 750 GPU或Intel CPU硬件在GIMP上运行stable diffussion插件进行AI绘图

安装步骤&#xff1a; 1. clone代码&#xff1a; git clone https://gitee.com/cslola/openvino-ai-plugins-gimp.git 或者直接到github上下载最新 git clone https://github.com/intel/openvino-ai-plugins-gimp.git2. 安装python以来库文件 :: run install script open…

OpenWRT 实现Exsi8单个公网ip管理与访问

一台Dell R720机器 内存256G(64G*4)硬盘SSD 8T(1T*8)搭建了一个裸金属k8s集群(对比阿里云单台4核8G的费用不相上下) 机房上架提供了一个公网ip 需要一个公网ip能实现exsi虚拟机管理 又可以让虚拟机实现web访问 是终通过OpenWRT实现 OpenWRT实现步骤 1、官网访问并下载img镜…