C++ 图论之Floyd算法求解次最短路径的感悟,一切都是脱壳后找最值而已

公众号:编程驿站

1. 前言

抛开基因的影响,学霸和学渣到底是在哪一点上有差异?

学霸刷完 200 道题,会对题目分类,并总结出解决类型问题的通用模板,我不喜欢模板这个名词,感觉到投机的意味,或许用方法或通用表达式更高级一点。而事实上模板一词更准确。

每一道题目在描述时,会套上一堆场景说词,可以说是契合真正的应用领域,或者说是出题人的故弄玄虚,弄了一些花里胡哨的迷糊你的外表,这时考核的不是专业知识,而是语文阅读能力。一旦脱出外壳,露出来的底层需求,就是书本上最基础的知识。

小学生学乘法表后,老师会布置很多应用题,不管应用题目的描述如何变化,一旦语文阅读理解过关,剩下的就是套用九九乘法表。为什么学霸学起来一直很轻松原因就在这里,做道时看山不是山。而学渣总是认为一道题目就是一个新知识,疲于学习,永无止境地追赶,停留在看山是山的境界。

为什么说这些?

这段时间写最小生成树、次最小生成树以及最短路径和次最短路径。总结一下,应该不难发现。本质就是在群体数据中找最小值和次最小值,这是最最基础的最值算法思想。如果是在一维数组中找最大值、最小值,只要有点语言基础的都能解决。

代码结构如下:

#include <bits/stdc++.h>
using namespace std;
int main() {
	//一维数组
	int nums[5]= {5,3,1,8,2};
	//存储最大值
	int maxVal_1=nums[0];
	//存储最小值
	int maxVal_2=nums[0];
	//遍历数组
	for(int i=0; i<5; i++) {
		//是否大于最大值
		if( nums[i]>maxVal_1 ) {
			//原来的最大值必然退居成第二大值
			maxVal_2=maxVal_1;
			//如果大于最大值,必然成为最大值
			maxVal_1=nums[i];
		} else if(nums[i]>maxVal_2) {
			//如果大于第二大的值,成为第二大值。
			maxVal_2=nums[i];
		}
	}
	cout<<maxVal_1<<"\t"<<maxVal_2<<endl;
	return 0;
}

其中玄机很简单。公司里空降了一位新领导,如果级别比现任的最高领导的级别高。则现任最高领导成为二把手,新领导成为一把手。如果新领导只比公司现任的二把手高,则挤掉二把手,成为新的二把手。

找最值算法本质,确定一个值,然后查找是否有比此值更大或更小的值,多重选择而已。

当问题变成找最小生成树,次最小生成树、最短路径,次最短路径时……

算法的思想本质没有发现变化,只是遍历的对象变成了图结构或树结构。虽然算法的底层策略不变,但因图结构比线性结构复杂的多,遍历过程中面临的选择也增多,如何选择,如何存储就变得稍难一点。

最短路径常用的算法为Floyd、Bellman、SPFA、Dijkstra。既然能找出最短路径,当然是能找出次最短路径的。下面将分别使用Floyd算法,细聊如何找出次最短路径。

2. Floyd算法

Floyd算法不甚了解的读者可以查阅本公众号里的《C++图论之常规最短路径算法的花式玩法(Floyd、Bellman、SPFA、Dijkstra算法合集)》一文。

使用Floyd算法求解最短路径时,顺手也能求解出次最短路径,下面捋捋这个过程。以下面的图结构为案例。

1.png

邻接矩阵存储存初始时,节点之间的权重关系。0表示自己和自己的距离,INF表示两节点间无直接连接,数值表示两节点的连接权重。Floyd是多源最短路径算法。算法结果需要记录任意两点间的距离,二维数组是较佳的选择。

现在除了要求解最短路径,还需要求解出次最短路径。则有两种存储方案:

  • 三维数组。
  • 两个二维数组。

三维数组本质是多个二维数组在空间深度上的叠加。如下图,所有二维数组的ij坐标描述任意两个节点的编号。z

  • 45
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Floyd算法是一种用于求解任意两结点最短路径的动态规划算法。下面是使用C++实现Floyd算法求解最短路径问题的代码示例: ```cpp #include <iostream> #include <vector> #define INF 99999 // 使用Floyd算法求解任意两结点的最短路径 void floydWarshall(std::vector<std::vector<int>>& graph, int n) { std::vector<std::vector<int>> dist(n, std::vector<int>(n)); // 初始化距离矩阵 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { dist[i][j] = graph[i][j]; } } // 更新距离矩阵 for (int k = 0; k < n; k++) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (dist[i][k] + dist[k][j] < dist[i][j]) { dist[i][j] = dist[i][k] + dist[k][j]; } } } } // 打印最短路径 std::cout << "最短路径矩阵:" << std::endl; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (dist[i][j] == INF) { std::cout << "INF "; } else { std::cout << dist[i][j] << " "; } } std::cout << std::endl; } } int main() { int n = 4; // 结点数量 std::vector<std::vector<int>> graph = { {0, 5, INF, 10}, {INF, 0, 3, INF}, {INF, INF, 0, 1}, {INF, INF, INF, 0} }; floydWarshall(graph, n); return 0; } ``` 以上代码中,`graph` 是一个邻接矩阵表示的图,`INF` 表示两个结点之间不存在直接连接。`floydWarshall` 函数使用Floyd算法计算任意两结点的最短路径,并将结果存储在 `dist` 矩阵中。最后,我们打印出最短路径矩阵。 在 `main` 函数中,我们测试了一个示例图,并输出了最短路径矩阵。 希望这个代码示例能够帮助到你!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一枚大果壳

码文不易,晚上熬夜需要点咖啡钱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值