最短路

记号

为了方便叙述,这里先给出下文将会用到的一些记号的含义。

  • nn 为图上点的数目,mm 为图上边的数目;

  • ss 为最短路的源点;

  • D(u)D(u)ss 点到 uu 点的 实际 最短路长度;

  • dis(u)dis(u)ss 点到 uu 点的 估计 最短路长度。任何时候都有 dis(u)D(u)dis(u) \geq D(u)。特别地,当最短路算法终止时,应有 dis(u)=D(u)dis(u)=D(u)

  • w(u,v)w(u,v)(u,v)(u,v) 这一条边的边权。

松弛

先介绍一些算法要用到的松弛(Relaxation)操作。

对于边 (u,v)(u,v),松弛操作对应下面的式子:dis(v)=min(dis(v),dis(u)+w(u,v))dis(v) = \min(dis(v), dis(u) + w(u, v))。 这么做的含义是显然的:我们尝试用 SuvS \to u \to v(其中 SuS \to u 的路径取最短路)这条路径去更新 vv 点最短路的长度,如果这条路径更优,就进行更新。

多源最短路

Floyd算法

我们用Floyd算法解决多源最短路问题:

int dist[400][400];
void Floyd(int n) {
    for (int k = 1; k <= n; ++k)
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= n; ++j)
                dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
}

四行代码,简洁明了。Floyd本质上是一个动态规划的思想,每一次循环更新经过前k个节点,i到j的最短路径

单源最短路

例题:https://www.luogu.com.cn/problem/P4779

Bellman-Ford算法

时间复杂度是O(nm)O(nm)

SPFA算法

Shortest Path Faster Algorithm (SPFA)),国际上一般认为是队列优化的Bellman-Ford 算法,一般仅在中国大陆被称为SPFA,是一个用于求解有向带权图单源最短路径的算法

Dijkstra算法

Dij用于单源最短路基于一种贪心的思想,适用于一张没有负边的图。若有负边 (有边边) 则要用到上面的两种算法了。

过程

将结点分成两个集合:已确定最短路长度的点集(记为 SS 集合)的和未确定最短路长度的点集(记为 TT 集合)。一开始所有的点都属于 TT 集合。

初始化 dis(s)=0dis(s)=0,其他点的 disdis均为 ++\infty

然后重复这些操作:

  1. TT 集合中,选取一个最短路长度最小的结点,移到 SS 集合中。

  2. 对那些刚刚被加入 SS 集合的结点的所有出边执行松弛操作。

证明

QED

实现

例题

L2-001 紧急救援 多条最短路,点权和最大

最后更新于

这有帮助吗?