一.floyd算法是什么?
floyd算法就是用来求图中任意两点最短路径的,这里举一个例子,如何求下图中任意两点间的最短路径呢?
我们用一个二维数组e[i] [j]来存储上面这个图所表示的意义。这里规定一个顶点到自己的值是0,顶点之间无法到达的值是∞。
这里我们要想一下,如何获得两点之间的最短距离呢?只能在这两个点中间再插入一个新的顶点使得缩短原来起点到终点的距离。我们在看上面的示例,如何求得两点间最短距离呢?只有当两点之间不能通过找到新的中转点来缩短距离为止。
现在思考一个问题:如果只允许经过一号顶点,求任意两点之间的最短距离,该怎么求?只需要判断e[i][1]+e[1][j]是否比e[i][j]小即可。e[i][1]+e[1][j]表示经过顶点1中转之后i到j的距离,e[i][j]表示i直接到j的距离(如果不存在那就是∞,前面已经提到了)。代码段如下:
for(i=1; i<=n; i++){
for(j=1; j<=n; j++){
if(e[i][j] > e[i][1] + e[1][j])
e[i][j] = e[i][1] + e[1][j];//如果发现中转点,那么就更新i到j的距离
}
}
经过1号顶点的情况下,任意两点之间的最短路程更新为:
我们发现经过1号顶点的中转3到2、4到2、4到3的路程都变短了。
那么我们接着求一下,在只允许经过1号顶点和2号顶点的情况下的任意两点之间的最短距离,应该怎么做呢?上面是不是刚刚做了只允许经过顶点1的最短路径优化,那再多一个顶点2应该怎么思考呢?直接在刚在那串代码后面加上顶点2的情况即可。代码段如下:
for(i=1; i<=n; i++){
for(j=1; j<=n; j++){
if(e[i][j] > e[i][1] + e[1][j])
e[i][j] = e[i][1] + e[1][j];
}
}
for(i=1; i<=n; i++){
for(j=1; j<=n; j++){
if(e[i][j] > e[i][2] + e[2][j])
e[i][j] = e[i][2] + e[2][j];
}
}
可能会有疑问:“那如果有两个点中间并不存在顶点1和顶点2呢?”。那也不影响结果,因为上面的代码更改的是能够通过顶点1和顶点2缩短路径的情况,其他情况的值仍然不变。
在只允许经过顶点1和顶点2的情况下,任意两点之间的最短路径更新为:
很明显,这次使得1到3和4到3的路程变短了,同理只允许在经过顶点1、2、3进行中转的情况下,任意两点之间的最短距离应该怎么做?在上面代码的后面再加一套for循环即可。以此类推允许通过所有顶点进行中转,任意两点之间最终的最短路径怎么求?直接在原来的双层for循环外面再包一层中转点循环即可,代码段如下:
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];
}
}
}
那么这五行代码就是floyd算法的核心了,读者可以在反复看一看这个例子,这个例子源自于我看的一本书名为:《啊哈!算法》,这本书的电子版可以在微信公众号“羊卓的杨”中回复“啊哈”获得。
二.关于floyd算法:
1.用来求解多源最短路径问题。
2.时间复杂度是O(N^3)
3.不能解决负权回路的图,因为那样的图没有最短路径,例如:
这个图就根本不存在1到3的最短路径,因为每绕一圈就会减少1,永远找不到最小值。
三.floyd算法例题:
HDU-1869-六度分离
《羊卓的杨的算法笔记》:链接
哔哩哔哩/bilibili:羊卓的杨