在现实生活中也会经常碰到多源最短路的问题。比如说供货,我是一个连锁供应商的老板,我们的货从海外运过来,然后选择一个城市作为主要供货城市,别的城市的货源都由该城市提供,要求这个城市去其它城市的运输最便捷,这个城市的选择其实就是一个多源最短路问题。
解决多源最短路问题有两个思路,1是对每个节点使用单源最短路算法(dijkstra什么的),2就是采用floyd算法。这里主要回顾floyd算法。
说实话,在最近一系列的图的练习中,有一点对我来说还是蛮重要的,可能说这点挺白痴的,但还是想说出来。那就是对于邻接矩阵的理解。乍一看邻接矩阵挺好理解的,D[i][j] 不就是表示i点和j点之间的距离么。但是细细想一想,我们经常不经意的把i和j之间连通与D[i][j] 的值为正常值(不是0,-1或者正无穷这样的值)划等号。但其实这是非常错误的,邻接矩阵仅表示“直接”相连的两点之间的关系(连不连通,权重是多少。)
而Floyd其实在一定程度上考察到了这一点,因为对于Floyd算法来说,对于所有K*K范围内的矩阵来说,其实都已经不算是邻接矩阵了,而是直接表示当前遍历程度(用K表示)下两个点之间的最短距离。Floyd通过不断更新邻接矩阵,慢慢将i与j(i与j在0到n-1内随意取值)之间的距离进行改变,最终当K取到n-1时,所有距离更新完毕,这时如果我们想知道某两个点之间的最短距离,直接进行遍历就好了。
说完小坑之后,我们一步步的说一下具体思路。先从整个邻接矩阵D的最小的子矩阵开始,D[0][0] 为1*1矩阵,也是第一个元素,没什么好说的跳过。然后是2*2矩阵,也没什么好说的,因为都是1对1的元素,和邻接矩阵没有区别。到了3*3矩阵就开始有变化了,因为D[i][j] 和D[i][k]+D[k][j] 开始不一定相等,于是我们需要逐个遍历并把D中对应的位置填上两者中的较小值。一直重复整个过程,直到整个矩阵更新完毕。
这是整个算法的python代码,假设图是无权图。
def floyd(n,mat):
for k in range(n):
for i in range(n):
for j in range(n):
if i==j or i==k or j==k:
continue
pos = get_pos(i,j)
a = mat[get_pos(i,k)]+mat[get_pos(k,j)]
b = mat[get_pos(i,j)]
if a<b:
mat[pos] = a
return mat
其中调用了一个get_pos(a,b)函数,源码如下:
def get_pos(a,b):
if a>=b:
return int(b+a*(a+1)/2)
else:
return int(a+b*(b+1)/2)
很容易看到,这个算法的时间复杂度是O(n^3)可以说复杂度是比较高的了,所以我用python做oj上的题老是超时!!!!!烦躁。
真的该严肃考虑一下是否要把cpp这种语言搞一下了,不然真的太烦了。