这大概是图论最基础的算法之一吧,本篇主要介绍佛洛依德(floyd)求图中任意两点之间的最短距离
弗洛伊德(Floyd)
采用邻接矩阵存图,n*n的矩阵存储点到点的最短距离
这里首先介绍一下动态规划(dp)的思想,给出三个点v1 v2 v3,你已经知道v1到v2的最短距离为1,v2到v3的嘴短距离为2,v1通过v2再到v3的最短距离显然为1+2,而在你存贮中的v1到v3却有可能比3长,有可能比3短,也可能就是3,如果比3长,显然需要更新这个数据,没错,Floyd就是不断的利用中间点来更新起点和终点之间的最短距离,最后达到求出任意两点的最短路长度的算法,他也是本篇介绍的算法中唯一一个不是求单源最短路径的算法(单源最短路径只能求出给定一点到其他点的最短路,而无法得知任意两点之间的最短路,看不懂不要紧,看到后面会明白的)
上图,图中是我们建完图所得到的初始n*n数组,这里要额外讲一个小技巧,在我们没有开始输入边的信息的时候,所有的点都是不相连的,所以,这个时候应该初始化矩阵内全为无限大,当然我们下意识的就想到遍历一遍都给他一个超大的值来表示不能到达,没错,介绍一个好用的函数,memset,使用之前要包括头文件
#include<string.h>
memset(mem,0x3f,sizeof(mem))
这个函数其实是对字节进行操作,第一个参数是地址,这里也就是mem数组的名字,0x3f其实就是63,众所周知一个字节有8比特,0x3f其实就是01111111,其实就是把这个字节变成011111111,这样得到的int或者long类型就会是一个很大的数,不赘述,不懂的自己搜索引擎,sizeof(mem)就是mem数组所占长度,这个参数的意思就是对给定位置(第一个参数)后面的第三参数的长度的字节进行初始化!另外需要提醒的是,此函数虽然方便,但是速度较慢,如果卡常,建议手写初始化。
主要算法,其实就是个三层循环,第一层k枚举的是中转点,第二层i枚举起点,第三层j枚举终点,只要以k为中转点可以更新i到j的距离,那就更新,时间复杂度n的三次方,比较暴力,一般不常用,但是还是要理解动态规划的思想!(引用我认为讲的最好的一段话:最开始只允许经过1号顶点进行中转,接下来只允许经过1和2号顶点进行中转……允许经过1~n号所有顶点进行中转,求任意两点之间的最短路程。用一句话概括就是:从i号顶点到j号顶点只经过前k号点的最短路程。)思考一下如果先枚举起点,再枚举中间点会出什么问题嘻嘻。
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(e[i][j]>e[i][k]+e[k][j])
e[i][j]=e[i][k]+e[k][j];
是不是很简单啊,如果还没明白自己画一个图模拟一遍就懂啦(图源网络)!