最短路径经典算法其三——Floyd
前言
hello,大家好吖,继我们上次讲了最短路径经典算法的 Dijkstra 和 Bellman-Ford 算法之后,相信大家对于最短路径的求解方法已经有了一些概念和基础,还有点迷糊的可以顺着代码的思路去画个图或者让程序打印出每一步的中间结果,就可以很明显地看出执行过程啦~
今天我们来讲最短路径经典算法其三—— Floyd算法。Floyd是多源多点的最短路径求解算法,之前讲的两个都是单源单点,如果要求任意一个节点A到节点B的最短路径,对于n个节点的无负环图我们需要运行n次Dijksta或者Bellman-Ford才可以得到所有可能的路径。所以今天讲的Floyd对于那种稠密图,即节点很多,节点间的连接也很多的图来说效率更高,一次求解便可以得到任意节点到其他节点的最短路径。
算法代码模板和原理讲解
Floyd算法的代码模板相比其他两个简单的多,本质上就是三重循环的贪心求解过程:
for k in range(N): # 可使用的节点集合范围0~n-1
for i in range(N): # 起点
for j in range(N): # 终点
ad_mat[i][j] = min(ad_mat[i][j], ad_mat[i][k]+ad_mat[k][j])
请记住上面的模板,很多题目的解都可以直接套用,复杂一点的可能需要增加一些判断条件,主体逻辑还是依旧。
我们可以知道,节点A到节点B的最短路径无非两种情况:
- 节点A直接到节点B最短
- 节点A通过一些中间节点C,D,…… 到达节点B最短
Floyd就是去在所有可能成为中间节点的集合里去寻找是否存在使得路径更短的节点组合:所以第一层循环可以理解为在所有节点组成的中间节点集合中找备选组(找备胎?? ),而后两层循环就是列举起点和终点的组合。
是不是有点穷举和贪心那味儿了~时间复杂度也很容易看出
O ( N 3 ) O(N^3) O(N3)
代码实现
我们来看看针对一般性最短路径的代码实现:
def Floyd(directed=True):
"""
Simple implement of Floyd Algorithm
Args:
directed (bool, optional): [whether directed graph or not]. Defaults to True.
"""
N, K, s, e = list(map(int, input().split())) # 节点数、连接数、起点终点标号
limit = 10000
ad_mat = [[limit for i in range(N)] for j in range(N)] # 邻接矩阵
for i in range(K):
u, v, w = list(map(int, input().split()))
ad_mat[u][v] = w
# 无向图
if not directed:
ad_mat[v][u] = w
for i in range(N):
ad_mat[i][i] = 0
# core
for k in range(N): # 可使用的节点集合范围0~n-1
for i in range</