最近考研复习到图的一些算法,但书上对这些算法解释只是一笔带过,更多的是如何做,如何使用。对于我这种又笨又固执的人来说,无疑非常难受,甚至一开始想不明白这个地方,但又说不出来,所以昨天很长时间都在思考这个算法是为什么。
看了很多博客,发现也鲜有人去写怎么理解,大都是代码加栗子,接下来说说我从另一个方面的理解,如果有不对的地方,希望大家指正。
首先定义一下图的结构
typedef struct {
char vex[MAXVERTEXNUM]; //顶点表
int edge[MAXVERTEXNUM][MAXVERTEXNUM]; //邻接矩阵
int vexnum; //当前图的顶点数
int edgenum; //当前图的边数
}Graph;
弗洛伊德算法的核心代码
for(int k=0; k<g.vexnum; k++) //最外层循环为中间顶点
for(int i=0; i<g.vexnum; i++) //i为起点
for(int j=0; j<g.vexnum; j++) //j为终点
if(dist[i][j] > dist[i][k]+dist[k][j]) {
//更新最短路径 若此处还需path矩阵应同步更新
dist[i][j] = dist[i][k] + dist[k][j];
}
核心代码非常简单,只有短短几行,便可寻找出图中任意两点之间的最短路径,真的非常佩服创造这些算法的前辈
接下来说说自己的一些理解:
- 从核心代码可以看出,每次更新的只是不超过3个点之间的最短路径,即在尝试向两点i,j之间插入第三点k。由此我产生了一个疑问,若两点之间的最短路径长度大于2,弗洛伊德算法是如何寻找到的呢?
- 两点之间的最短路径分为3种情况:无路径,路径长度为1或2(即有一个中间顶点),路径长度大于2(即有多个中间顶点)
- 对于前两种情况可以通过弗洛伊德算法很好的得到,对于第三种情况,例如i和j之间的最短路径为i–>k1–>k2–>…–>km–>j,通过对最短路算法的分析,显然得该路径中任意两点ki,ki+2的最短路径仍属于该路径即ki–>k(i+1)–>k(i+2),反过来说只要找到所有长度小于等于2的最短路径,就可以得到(组合为)任意两点之间的最短路径,因此(1)中的问题就解决了,也可以理解为弗洛伊德算法核心代码遍历的过程,对于比较长的最短路径来说就是不断寻找到中间顶点ki(1<=i<=m)的过程,而且寻找的顺序是无所谓的。