专栏文章

题解:P4779 【模板】单源最短路径(标准版)

P4779题解参与者 6已保存评论 5

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
5 条
当前快照
1 份
快照标识符
@mioscqhw
此快照首次捕获于
2025/12/03 00:21
3 个月前
此快照最后确认于
2025/12/03 00:21
3 个月前
查看原文

Solution

update on 2025.8.12:ED_BuilderSolusion->Solution。

思路

使用博客园效果更佳。
首先,题目说的很明白,这个广为人知的最短路算法就是 SPFA,它死了。这题会专门卡 SPFA,别问我咋知道的,在最劣情况下 SPFA 时间复杂度 O(n×m)O(n\times m),边权没有负数的情况下我们通常使用 dijkstra 算法,而在有负边权的情况下通常使用 ‌Bellman-Ford。
这题和简单版的唯一区别就是简单版可以 O(n2)O(n^2),然而这题需要使用更优的时间复杂度。
dijkstra 的实现过程:
用一个 queue 维护我们可以走到的点,dis[u] 表示从起点走到 uu 点的最短路径,我们每次遍历当前节点 uu 可以走到的节点 vv,若从 uu 走到 vv 节点更优,则更新 vv 的最短路,由于我们可以从 uu 节点走到 vv 节点,将 vv 节点丢入 queue 中。
我们可以举个例子:
n=4,m=4n=4, m=4
1234
queue1
dis0
初始时没有任何操作。
然后从起点遍历,点 11 至点 22 的边权为 22,先遍历到了点 22,发现我们从点 11 到点 22 最优,则更新从起点到点 22 的最短路,然后丢入队列。
1234
queue2
dis02
遍历到了点 33,点 11 至点 33 的边权为 33,发现我们从点 11 到点 33 最优,则更新从起点到点 33 的最短路,然后丢入队列。
1234
queue23
dis023
然后点 11 到不了其他点了,所以将队列的第一个元素点 22 拿出来进行遍历。
从节点 22 只能遍历到点 44,且可以更新最短路,丢入队列。
1234
queue34
dis0236
22 到不了其他点了,所以将队列的第一个元素点 33 拿出来进行遍历。
从节点 33 只能遍历到点 44,原最短路是 66,然而从点 33 去点 44 只要 44,可以更新最短路,丢入队列。
1234
queue4
dis0234
然后把点 44 拿出来,不能遍历,跳过。
队列空了,结束。
最终结果:
1234
queue
dis0234
但是为什么不能处理负边权?
因为 dijkstra 基于贪心思想,遍历到一次的节点不会再次更新。
上面的过程是 dijkstra 的朴素做法,复杂度 O(n2)O(n^2),所以我们需要堆优化。
由于 dijkstra 是基于贪心的算法,因此我们可以用 priority_queue 优化。
注意事项:
  • 由于我们 disdis 要取 min\min 值,所以 disdis 初始化为一个极大值,通常为 inf\inf
  • 题目是有向边。
代码:
CPP
void dijkstra(int s)
{
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
    memset(dis, 0x3f, sizeof(dis)); // 初始化
    dis[s] = 0;
    q.push({dis[s], s}); // 将起点加入队列
    while (!q.empty())
    {
        int u = q.top().second;
        q.pop();
        if (vis[u]) // 若 u 已访问,跳过
            continue;
        vis[u] = true;                          // 标记为已访问
        for (int j = 0; j < adj[u].size(); j++) // 遍历 u 可以去的所有点
        {
            int v = adj[u][j].to, w = adj[u][j].w;
            if (dis[v] > dis[u] + w) // 若从 u 去 v 更优,更改最短路,丢进队列
            {
                dis[v] = dis[u] + w;
                q.push({dis[v], v});
            }
        }
    }
}

评论

5 条评论,欢迎与作者交流。

正在加载评论...