以前学过的东西不求甚解,没有完全掌握要旨,所以重新理解了一下。
算法都是比较容易的。
最短路
Floyd
实际上在枚举到k时,dist[i][j]表示的是从i到j,除起点和终点外均小于k的路径中的最短路。
Dijkstra
时间复杂度
n
l
o
g
n
n logn
nlogn
边权不可为负(对于费用流的有特殊解法)
一个显然的结论是:一个点的最短路一定是另外一个点的最短路更新的。
过程:
初始所有点均为白点。每次选择f最小的白点作为当前点。
枚举当前点的出边,用当前点更新其余点的f。
将当前点染黑。重复上述过程直至所有点都是黑点。
证明:
把最短路更新过的点开成黑点,
每次f最小的白点的最短路显然也是确定的(被黑点),而且此时任何其余白点不可能继续更新其f值。
用优先队列优化。
Spfa
spfa的时间复杂度是
O
(
n
m
)
O(nm)
O(nm)的
关于正确性的证明:过程类似于
b
f
s
bfs
bfs,如果一个点再次入队,一定说明S到这个点的最短路经过的边数增加了,
对于没有负圈的图,最短路上不可能经过重复的边,因此s->x最短路经过边数不超过n-1,那么显然任何点入队应该不超过n-1次,所以复杂度不超过O(nm)。
这个结论告诉我们,如果spfa算法中有一个点入队了n次及以上,原图一定存在负圈。
生成树
最小生成树的性质
切割性质:
将点集V分成S和V-S,一端在S内另一端在V-S内边权最小的边,一定出现在最小生成树中。
根据这个性质,对应求解最小生成树算法应运而生。
Prim
随机挑一个点,然后根据切割性质做,类似于dijkstra算法的优化,用堆即可。
Kruskal
该算法的时间复杂度的瓶颈在于排序
正确性容易理解,可以用反证法证明(本人感觉可以用切割性质证明)
Boruvka
利用了切割性质。