最短路
在图论中最短路径是两个节点之间经过的边权值之和最小的路径,是一种在图上的搜索,满足最优子结构(可以使用动态规划和贪心算法)
最优子结构:最短路径的子路径也是最短路径(有可以到达的负环的图不满足最优子结构)
单源最短路问题
找到从给定源节点到其它节点的最短路径
相关算法
Floyd
动态规划的思想,是多源的(算出了每两个节点的最短距离),复杂度O(n^3)
用f[k][x][y]表示中间只经过1~k的点的最短路,转移为:f[k][x][y]=min(f[k-1][x][y]/*x->y不经过k点的情况*/,f[k-1][x][k]+f[k-1][k][y]/*x->y经过k点情况*/)
第k层依赖k-1层,每一层x,y都要遍历完,自底向上动态规划,复杂度O(n^3)
Bellman_Ford
动态规划的思想,是单源的,复杂度O(nm)
Bellman-Ford 算法的基本思想是对所有边进行松弛操作,每次松弛操作都会更新一些最短路径的估计值。算法进行 n-1 轮松弛操作,其中 n 是图中顶点的数量。在每一轮松弛操作中,算法都会遍历图中的所有边,对每一条边进行松弛操作。
可以这么想:f[k][x]表示从起点到x最多经过k条边的最短路
转移为:
第k层依赖k-1层,每一层要遍历完所有边(没有入度的边也要更新),自底向上动态规划,复杂度O(nm)
//Floyd、Bellman_Ford实际用的时候,不用分层,分层隔绝了每层先更新部分对后更新的依赖的影响,这里的影响是好的所以不用分层
SPFA(Shortest Path Faster Algorithm)
bellman_ford的队列优化,它利用了这样一个事实:在进行松弛操作时,只有那些在上一轮松弛操作中发生变化的顶点才可能对其他顶点产生影响。
基于这个观察,SPFA 算法使用一个队列来维护所有可能对其他顶点产生影响的顶点。
SPFA 算法的时间复杂度取决于具体的图结构和边权分布。在最坏情况下,它的时间复杂度与 Bellman-Ford 算法相同,为 O(nm),但在实际应用中,SPFA 算法通常比 Bellman-Ford 算法快很多。
Dijkstra
贪心思想,是单源最短路径问题的。它不能处理带有负权边的图。
每次选择距离源点最近的未确定顶点,然后更新与其相邻顶点的最短路径长度。
复杂度O(n^2+m),其中一个n是n次贪心,另一个n是找最近点,m是所有边会遍历一遍。
找点可以维护一个优先队列等操作优化,比Bellman_Ford快。
因为贪心算法只看下一步,所以它不能处理带有负权边的图。比如下图:它会按序号更新,不会更新已经遍历的点,下面的情况就出错了
拓展(思考)
-
对于动态规划,重要的是能设计出dp的顺序
-
一般图的最长路因为没有最优子结构所以是NP-hard问题,只能硬搜
-
DAG(有向无环图)上,最短、最长路都满足最优子结构,所以能用dp,先拓扑排序,按dp顺序转移
建模
将问题转化为图论问题来求解是一种常见且强大的建模方法
(比如一些我还不会的算法:网络流算法可以用来解决许多看似与图论无关的问题,如二分图匹配、最大权闭合子图、最小割等。此外,线性规划也可以转化为网络流问题来求解。)
DAG上的动态规划
一些二元关系可以转换为图,比如:
有n(n\leq 30) 种砖块,已知三条边长,每种都有无穷多个。要求选一些立方体摞成一根尽量高的柱子(每个砖块可以自行选择一条边作为高),使得每个砖块的底面长宽分别严格小于它下方砖块的底面长宽,求塔的最大高度。
可以建图求最长路。
UVa 437 巴比伦塔 The Tower of Babylon
差分约束
可以写为
可以建模为一个图,有j指向i的边,c_k是权值,x_i,x_j是到起点的最短距离,那么一定满足上面的不等式(如果不满足就需要更新了)。所以只要在这个图中,有所有上面类似的不等式的边,只要这些边能到达(更新解),这些节点的最短距离就是这些变量的一组解。
这些边不一定连通,我们需要加入不影响结果的边让图连通
可以加入一个源点,指向其它所有点,
因为所有相当于加入了(反映在图形上是所有点的最短路均小于等于0)。
但是,这并不影响我们求解差分约束系统。因为如果x是该差分约束系统的一组解,那么对于任意的常数k,x+k也是该差分约束系统的一组解。所以我们可以通过求出满足的一组解,然后再加上一个常数k来得到满足任意条件的一组解。
例题:poj1201题目链接
我们再用念念不忘的动态规划分析上面的两种建模
巴比伦塔一题:以A为底座的最高塔上有B,那以B为底座的部分也是最高塔
差分约束?差分约束系统本身并不具有最优子结构。
差分约束系统是一种常用的建模方法,它可以将一些实际问题转化为线性规划问题。虽然差分约束系统本身并不具有最优子结构,但它可以被归约为单源最短路径问题,而最短路径问题具有最优子结构性质。因此,我们可以使用基于动态规划的算法,如 Bellman-Ford 算法来解决差分约束系统问题。
总之,建模过程中我们可以选择合适的数学模型来描述实际问题。这些数学模型可能具有不同的性质,我们可以利用这些性质来设计相应的算法来求解问题。
视频:【最短路:floyd、bellman-ford、dijkstra、spfa】 https://www.bilibili.com/video/BV1Jg4y1G7N1/?share_source=copy_web&vd_source=a3420898ac044db8aef7bc6cd32b8b1f