BISHI109 邮递员送信¶
中等通过率 72.39%python3样例通过牛客 AC
讲解章节:最短路、图论进阶:k 短路与关键路径
一句话
从 1 号点分别往返 2..n 各一次,求总最短时间。
解题思路¶
这题考什么¶
「所有点到某个源点的最短路」= 在反向图上从源点跑一次单源最短路。
总时间 = Σ_{v=2..n} ( dist(1 -> v) + dist(v -> 1) )。
- 前半部分:在原图上从 1 跑一次 Dijkstra,求出 dist(1 -> v);
- 后半部分:dist(v -> 1) 若逐点跑就是 n 次 Dijkstra(n=1000 时 1e8 级别), 正确做法是把所有边反向建图,在反图上从 1 跑一次 Dijkstra, 得到的 rdist[v] 恰好就是原图里 v -> 1 的最短路。
于是只需要两次 Dijkstra。
数据规模与复杂度¶
n <= 1e3,m <= 1e5,w <= 1e4。两次堆优化 Dijkstra 各 O(m log m)。 (n 只有 1000,朴素 O(n^2) 的 Dijkstra 也是 1e6 能过, 但 m 到 1e5 时堆优化更稳,而且是通用写法。)
Python 的坑¶
- Dijkstra 用 heapq,标准「懒删除」写法:弹出 (d, u) 时若 d > dist[u] 就 continue,heapq 没有 decrease-key,这是唯一正确的姿势;
- 两张 CSR 邻接表(正图、反图)共用同一套构建代码,写成函数复用。 CSR 即 Compressed Sparse Row(压缩稀疏行):不给每个点单独开一个 list, 而是把所有边首尾相接铺进一个扁平数组,再用 start 数组记下每个点的边 从哪里开始、到哪里结束。省掉 n 个小 list 对象的构造与内存开销; 不要用 defaultdict(list);
- 输入 3e5 个整数一次 read().split()。
坑在哪¶
- 题面保证「任意两点互相可达」,所以不会出现 INF; 但保险起见仍按 INF 处理(真出现就说明数据违背题面);
- 道路是单向的,反图必须真的把 u、v 换个位置重新建表, 不能直接复用原图;
- 可能有重边(样例里 3->5 出现两次,权都是 6),Dijkstra 天然处理;
- 答案可达 1e3 * 2 * (1e3 * 1e4) = 2e10 级别,C++ 要 long long;Python 无忧。
参考实现¶
[:octicons-arrow-left-16: BISHI108](BISHI108.md) [BISHI110 :octicons-arrow-right-16:](BISHI110.md)