基础图论算法
首先还是感谢 Alex_Wei 的博客 图论基础.
这篇博客可以理解成学习笔记之类的.所以记叙比较散乱是正常的.嗯.
一.最短路
以下内容,提最短路时若不做特殊说明,默认图是 无负环的存在负权有向图.
结论
- 最短路中不存在环.
若存在环,只能是负环.
- 单源最短路中,源点到图中任意一点的最短路最多有 \(n-1\) 条边.
考虑 \(n-1\) 条边构成图中可能存在的最小的链.若存在超过 \(n-1\) 条边,则路径上有环.这与 结论 1 矛盾.
- 最短路树
对于每个点的最短路,考虑将它最短路上的前驱节点(若有若干,选择其中一个) \(v(dis_u=dis_v+w)\) 认作其父亲.则若所有点对源点都可达,这样会形成一种树形结构满足源点出发的任意一条路径都是最短路.我们叫他最短路树.
最短路树不止一种.若保留所有的
算法
SPFA
SPFA 是 Bellman-Fold 算法的队列优化.
其核心思想是对全点做 \(n-1\) 轮松弛.即遍历边 \(e(u \rightarrow v, w)\),检查若 \(dis_v>dis_u+w\),令 \(dis_v \leftarrow dis_u+w\).
松弛 \(i\) 轮后,\(dis_u\) 表示源点到 \(u\) 经过边数不超过 \(i\) 的最短路长度.
SPFA 判断负环
初始时,将全点丢入队列,\(dis\) 赋为 \(0\).执行 SPFA 并更新每个点的 入队次数,若发现某点入队次数 \(\ge\) \(n-1\),则原图存在负环.
入队次数,其实等于最短路经过的边数.当第 \(x\) 次入队时,一定有路径边数 \(\ge x\).否则它肯定会在之前的轮次更新.
差分约束系统
考虑一组变元 \((x_1, x_2, x_3, ..., x_n)\) 的取值:
若存在若干组限制 \(x_i+d \ge x_j\).如何构造满足所有限制的解.
发现 \(x_i+d \ge x_j\) 形如最短路里的三角形不等式:
对于任意一种单元最短路,若存在边 \(e(u \rightarrow v, w)\),一定有 \(dis_u+w \ge dis_v\).
于是我们对于每组限制,建边 \(e(x_i \rightarrow x_j, d)\),然后进行最短路算法即可.
为了防止存在单元最短路无法扩展到的点,通常,我们会建立超级源点 \(S\),并对所有点建边 \(e(S \rightarrow u, 0)\).
这显然不会影响答案的正确性.只是限制了求解出的 \(x_i\) 小于等于给 \(S\) 赋值的初始距离 \(dis_S\).
考虑最短路求得解的特殊性:
最短路求得差分约束的解满足为所有 \(x_i \le dis_S\) 的最大解.
考察差分约束建模后产生的最短路树,若将任意某些 \(x_i+1\),则必定存在其某个 \(x_i\) 最短路树上的父亲与 \(x_i\) 不满足三角形不等式.
同理,最长路求得的解是满足所有 \(x_i \ge dis_S\) 的最小解.
Dijkstra
适用于非负权图最短路.
每次选择距离最短的节点,将其标记为已经求解了最短路的节点,然后用其更新其他没有标记的节点.
在非负权图中,对于一种最短路树,可以保证其父亲的距离一定小于等于自身的距离.归纳法即可证明 Dijkstra 算法的正确性.
值得注意,使用堆优化的 Dijkstra 的算法时间复杂度为 \(O(m\log m)\).当 \(m\) 接近 \(n^2\) 时,使用不加堆优化的 Dijkstra 算法更优,复杂度为 \(O(n^2)\).
01 Bfs
是 Dijkstra 算法在特殊图上的一种变式.
考虑一张图只有 \(0/1\) 两种边权.我们使用 deque 进行 Bfs.每次取出队头,若碰到 \(0\) 边,将新节点放入对头;若碰到 \(1\) 边,将新节点放入队尾.
结论:第一次被更新时的距离即是每个节点的最短距离.
证明:
- 在 01 Bfs 中,队列里的点距离按从小到大排列.
- 在 01 Bfs 中,当前队列里只会有两种距离 \(d,d+1\) 的点.若当前局面满足 1,2,只会更新出距离为 \(d\) 或 \(d+1\) 的点.故之后的状态也满足 1,2.
所以 01 Bfs 在 01 边权的图上模拟了 Dijkstra.

浙公网安备 33010602011771号