公众号:编程驿站
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
算法求解最短路径时,顺手也能求解出次最短路径,下面捋捋这个过程。以下面的图结构为案例。
邻接矩阵存储存初始时,节点之间的权重关系。0
表示自己和自己的距离,INF
表示两节点间无直接连接,数值表示两节点的连接权重。Floyd
是多源最短路径算法。算法结果需要记录任意两点间的距离,二维数组是较佳的选择。
现在除了要求解最短路径,还需要求解出次最短路径。则有两种存储方案:
- 三维数组。
- 两个二维数组。
三维数组本质是多个二维数组在空间深度上的叠加。如下图,所有二维数组的i
和j
坐标描述任意两个节点的编号。z