1 条题解
-
0
题目大意
给定一个有向图, 个点 条边,边权为正整数。
再给定 个特殊点,要求找出这 个特殊点之间两两最短距离的最小值。注意:是有向图, 到 和 到 的路径长度可能不同,也可能不存在路径。
样例分析
样例1
6 7 3 1 5 3 2 3 5 1 4 3 5 3 2 4 6 5 4 3 7 5 6 4 1 3 6特殊点:
计算:
- :路径 ,长度
- :路径 ,长度 (或 长度 )
- :无路径
- :无路径
- :无路径
- :无路径
最近点对是 ,距离 。
思路分析
1. 暴力做法(不可行)
直接枚举 个点的所有点对,对每个点对跑单源最短路。
复杂度:,当 很大时不可行。2. 多源最短路优化
我们并不需要所有点对,只需要找到最小值。可以利用这个性质进行优化。
关键观察:最近的特殊点对 一定满足 和 在某个最短路树中相邻(在路径上相邻)。
标准解法:多源 Dijkstra
算法步骤
- 建立一个超级源点 ,连接到所有 个特殊点,边权为
- 从 开始跑 Dijkstra
- 当扩展到一个特殊点 时,记录它是从哪个特殊点 扩展过来的
- 如果 和 是不同的特殊点,那么 就是一个候选的最近点对
原理:
在 Dijkstra 算法中,当我们第一次遇到一个特殊点 时,它一定是离源点 最近的特殊点之一。
如果 是从另一个特殊点 扩展过来的,那么 到 的路径就是当前已知的最短路径之一。
具体实现细节
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<ll, int> pli; const ll INF = 2e18; ll solve() { int n, m, k; cin >> n >> m >> k; vector<vector<pair<int, int>>> g(n + 1); for (int i = 0; i < m; i++) { int u, v, w; cin >> u >> v >> w; g[u].emplace_back(v, w); } vector<int> special(k); for (int i = 0; i < k; i++) { cin >> special[i]; } ll ans = INF; // 从超级源点S=0开始 vector<ll> dist(n + 1, INF); vector<int> from(n + 1, -1); // 记录是从哪个特殊点扩展来的 priority_queue<pli, vector<pli>, greater<pli>> pq; // 初始化:所有特殊点加入队列 for (int i = 0; i < k; i++) { int u = special[i]; dist[u] = 0; from[u] = u; // 从自己扩展来 pq.emplace(0, u); } while (!pq.empty()) { auto [d, u] = pq.top(); pq.pop(); if (d != dist[u]) continue; // 如果u是特殊点,且不是第一次被扩展(即从其他特殊点扩展来) if (from[u] != -1 && from[u] != u) { // 这里找到了一对特殊点 (from[u], u),距离为d ans = min(ans, d); } for (auto [v, w] : g[u]) { ll nd = d + w; if (nd < dist[v]) { dist[v] = nd; from[v] = from[u]; // 继承来源特殊点 pq.emplace(nd, v); } } } return ans == INF ? -1 : ans; }
算法正确性证明
设最近的特殊点对是 ,距离为 。
在 Dijkstra 执行过程中,当扩展到 时:- 如果 是从 扩展过来的,那么我们会发现这对点,距离为
- 如果 是从其他点 扩展过来的,那么 ,且 也是特殊点,这与 是最近点对矛盾
因此算法一定能找到最近的特殊点对。
复杂度分析
- 时间复杂度:,与普通 Dijkstra 相同
- 空间复杂度:
这比暴力 优化了很多。
注意事项
- 有向图:路径是单向的, 和 要分开考虑
- 无穷大处理:如果所有特殊点对都不可达,需要特殊处理
- 边权范围:,要用
long long存储距离
样例验证
样例2
7 7 4 5 3 10 6 2 7 1 2 6 5 4 2 4 3 4 1 7 3 7 2 4 1 2 5 3特殊点:
计算发现:
- :路径 ,长度 ;或 直接长度
- :路径 ,长度
最近距离是 。
总结
本题的关键在于:
- 识别出这是有向图多源最短路问题
- 利用 Dijkstra 的性质,在扩展过程中直接检测最近点对
- 通过超级源点技巧,将多源问题转化为单源问题
这种解法优雅地避免了暴力枚举,将复杂度从 降为 ,能够处理大规模数据。
- 1
信息
- ID
- 4445
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者