最短路径问题的三种算法:1.代码量极少的Floyd-Warshall算法

目录

一.图的概念:

二.图的存储:

三:Floyd-Warshall算法

1.主要思想:

2.算法核心:

3.代码实现(自己动手敲一敲哟):

4.上面那张图的最短距离求解完整代码:

最后:


一.图的概念:

在学习最短路径之前,我们得了解一下图的概念:

图,就是由顶点和边组成的一种数据结构,图不像树那样,图是允许有回路的,而且图还可以再进一步分为有向图和无向图(就是有方向跟没方向),途中的边的距离可以是整数(一般叫正权)也可以是负数(我们一般叫负权)等等。


这就是图(这里点与点间的距离默认为1,相等)


二.图的存储:

图的存储有几种方法,这里我们就介绍最简单的一种,其他几种我会在本专栏的后面几期进行介绍。

1.邻接矩阵法:(先以无向图为例)

当有n个点时,我们就创建一个(n+1)*(n+1)大小的空间(因为下标从1开始很方便,你懂的),然后把每个顶点到每个顶点的直接距离(就是不经过中间点的距离)都存到这个这个矩阵中,然后如果某个起点无法直接到达终点,我们就把值设为无穷。

例如:


有没有发现无向图的一个特点:邻接矩阵沿着i==j这条对角线对称。

这就是图的邻接矩阵存储法。

三:Floyd-Warshall算法

当我们找寻一个点到一个点的最短路径的时候,我们可以采用枚举的方法(太蠢了,你们这些大聪明肯定都不屑于用这种方法),那我们有没有什么更好的办法去得到两点之间的最短路径呢?

这是当然,我们站在巨人的肩膀上,那些前辈巨佬们肯定都帮我们想好了,接下来就介绍一种代码量极少的算法:Floyd-Warshall算法

1.主要思想:

我们求两个点之间的最短路径的时候,往往这两个点之间是没有直接连通的,我们就需要通过其他顶点来间接的访问到终点。

通过其他的顶点来访问终点,如果可以使得起点到终点的最终距离缩短的话,我们就称作这个过程完成了边的“松弛”(后面几种算法也会用到这种方法)。

2.算法核心:

Floyd-Warshall算法的核心就是尝试利用每一个点来对某两个顶点之间的距离进行松弛

是不是没听懂,我们用例子来分析一下

我们以下面这个图为例来讲解:(这是有向图哟)



假设我们要求的是顶点1到顶点4的距离,那么根据Floyd-Warshall算法的核心,我们首先以1号顶点为中间点来对所有的顶点间距离进行松弛:

首先一号顶点到其他顶点的距离通过本身是无法松弛的,那我们来看二号顶点,由于二号顶点到一号顶点的距离是无穷,那么很显然我们无法通过一号顶点对二号顶点到其他顶点的距离进行松弛。再看三号顶点,好像可以:三号顶点到一号顶点的距离为7,三号顶点到二号顶点的距离为无穷,那么我们先从3号顶点到1号顶点,再到2号顶点,结果路程为9,也就是完成了松弛!!!

同理,4号顶点到2号顶点、三号顶点的距离也可以通过一号顶点进行松弛。

以1号为中间顶点松弛完一轮的结果如下:


然后我们在一次通过2号、3号、4号顶点对图进行松弛,结果如下:



此时我们就得到了任意顶点到任意顶点的最短距离!!!!

3.代码实现(自己动手敲一敲哟):


//n为顶点个数,e为储存图的邻接矩阵数组

for(int i=1;i<=n;i++)//这层循环是控制以那个点为中间节点的
    for(int j=1;j<=n;j++)//下面两层是实现邻接矩阵的遍历的
        for(int k=1;k<=n;k++)
            if(e[j][k]>e[j][i]+e[i][k])
                e[j][k]=e[j][i]+e[i][k];

// 真就五行

4.上面那张图的最短距离求解完整代码:


#include <stdio.h>
#define inf 999999

//宏定义起点
#define start 1

//宏定义终点
#define destination 4

int e[51][51];
int book[51];
int main()
{
	int n, m;//顶点个数和边的个数
	scanf("%d%d", &n, &m);
//初始化邻接矩阵
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			if (i == j)
				e[i][j] = 0;
			else e[i][j] = inf;
		}
	}

//数据如矩阵
	int a, b,len;
	for (int i = 0; i < m; i++)
	{
		scanf("%d%d%d", &a, &b, &len);
		e[a][b] = len;
	}


	for (int i = 1; i <= n; i++)//算法核心代码,简便但复杂度大
		for (int j = 1; j <= n; j++)
			for (int k = 1; k <= n; k++)
				if (arr[j][k] > arr[j][i] + arr[i][k])//如果通过i点能够缩短j点到k点的最近距离,那么就更新最近距离
				{
					e[j][k] =e[j][i] + e[i][k];
				}
	printf("%d", e[start][destination]);
}

然后当我们拿着这样一种算法做在线oj题目的时候我们经常会发现超时了(不超时才怪,复杂度足足有n的三次方^_^)。

最后:

所以Floyd-Warshall算法只适用于数据量较少的情况,而且优势是能够算出整个途中所有的点对点之间的最短路径(当我们只求两个点的时候就有点浪费),下一期,我们就介绍一种时间复杂度更加完美的一种最短路径算法:Dijkstra算 法!!

如果这期的博客对你有所帮助的话,不要忘了点赞收藏加关注哟,你们的支持就是我前进的动力(一个赞一道题!!!),让我们下期再见。


  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值