番摊机器人 P6869 Putovanje 题解
作者:admin | 分类:番摊机器人 | 浏览:3 | 日期:2026年08月30日这是一道信息学奥赛中的经典最短路径变种题,结合你之前关注的图论最短路径、拓扑排序相关题解需求,以下是完整的题意分析、解题思路与代码实现。
题意解析
题目背景设定在一个由N个城市、M条双向道路组成的无向图中,每条道路有对应的通行耗时。旅行者从起点城市1出发,需要前往终点城市N,要求你计算满足以下条件的最短路径长度:
路径中必须经过至少一个指定的中间城市集合中的节点,同时路径总耗时最短。部分测试点存在重边、自环,需要在预处理阶段提前过滤,避免干扰后续路径计算。
核心解题思路
这道题不需要做复杂的路径枚举,用两次Dijkstra算法就能以极低的时间复杂度完成求解:
第一次以起点1为源点运行Dijkstra,得到数组dist1[],其中dist1[i]代表从起点1到城市i的最短距离。
第二次以终点N为源点运行Dijkstra,得到数组distn[],其中distn[i]代表从城市i到终点N的最短距离。
遍历所有指定的中间城市集合中的节点k,计算dist1[k] + distn[k]的最小值,这个最小值就是题目要求的、经过至少一个指定中间点的最短路径长度。
这个思路的时间复杂度为O(M log N),完全可以轻松应对N≤1e5、M≤2e5的大数据量测试用例,比直接枚举所有路径的暴力解法效率高出几个数量级。
完整C++实现代码
cpp
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = 1e18;
vector<ll> dijkstra(int s, int n, const vector<vector<pair<int, int>>>& g) {
vector<ll> dist(n + 1, INF);
priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<>> q;
dist[s] = 0;
q.emplace(0, s);
while (!q.empty()) {
auto [d, u] = q.top();
q.pop();
if (d > dist[u]) continue;
for (auto [v, w] : g[u]) {
if (dist[v] > dist[u] + w) {
dist[v] = dist[u] + w;
q.emplace(dist[v], v);
}
}
}
return dist;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
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);
g[v].emplace_back(u, w);
}
vector<int> stops(k);
for (int i = 0; i < k; i++) cin >> stops[i];
auto dist1 = dijkstra(1, n, g);
auto distn = dijkstra(n, n, g);
ll ans = INF;
for (int p : stops) {
ans = min(ans, dist1[p] + distn[p]);
}
cout << ans << endl;
return 0;
}
边界情况处理要点
提前过滤图中的自环:u和v相等的边直接跳过,避免Dijkstra算法中出现无效的距离更新。
重边自动适配:优先队列的松弛逻辑会自动保留两个节点之间权重最小的边,不需要提前手动去重。
数据类型选择:必须用long long存储距离,避免多条边累加后int类型溢出导致结果错误。
需要我为你补充这道题的多测试点分步调试指南,帮你快速定位提交时出现的RE/TLE/WA错误吗?