acwing.1137 选择最佳线路
有一天,琪琪想乘坐公交车去拜访她的一位朋友。
由于琪琪非常容易晕车,所以她想尽快到达朋友家。
现在给定你一张城市交通路线图,上面包含城市的公交站台以及公交线路的具体分布。
已知城市中共包含 n 个车站(编号1~n)以及 m 条公交线路。
每条公交线路都是 单向的,从一个车站出发直接到达另一个车站,两个车站之间可能存在多条公交线路。
琪琪的朋友住在 s 号车站附近。
琪琪可以在任何车站选择换乘其它公共汽车。
请找出琪琪到达她的朋友家(附近的公交车站)需要花费的最少时间。
输入格式
输入包含多组测试数据。
每组测试数据第一行包含三个整数 n,m,s,分别表示车站数量,公交线路数量以及朋友家附近车站的编号。
接下来 m 行,每行包含三个整数 p,q,t,表示存在一条线路从车站 p 到达车站 q,用时为 t。
接下来一行,包含一个整数 w,表示琪琪家附近共有 w 个车站,她可以在这 w 个车站中选择一个车站作为始发站。
再一行,包含 w 个整数,表示琪琪家附近的 w 个车站的编号。
输出格式
每个测试数据输出一个整数作为结果,表示所需花费的最少时间。
如果无法达到朋友家的车站,则输出 -1。
每个结果占一行。
数据范围
n≤1000,m≤20000,
1≤s≤n,
0<w<n,
0<t≤1000
题意
给你多个点,让你计算多个点中任意一点到一定点的距离最小值
思路一.
因为本题是多对一,我们可以采用反向建边的方法把问题转化为一对多的形式,这样就可以只用一次最短路求min
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int N = 1010,M = 2 * 20010;
int head[N], ver[M], edge[M], ne[M], d[N];
bool v[N];
int n, m, s, w, tot;
priority_queue<pair <int, int> >q;
void add (int x, int y, int z) {
ver[++tot] = y, edge[tot] = z, ne[tot] = head[x], head[x] = tot;
}
void dijkstra (int s) {
memset(d, 0x3f, sizeof d);
memset(v, 0, sizeof v);
d[s] = 0;
q.push(make_pair(0, s));
while (q.size()) {
int x = q.top().second; q.pop();
if (v[x]) continue;
v[x] = 1;
for (int i = head[x]; i; i = ne[i]) {
int y = ver[i], z = edge[i];
if (d[y] > d[x] + z) {
d[y] = d[x] + z;
q.push(make_pair(-d[y], y));
}
}
}
}
int main() {
while (cin >> n >> m >> s) {
int ans = INF;
memset(head, -1, sizeof head);
tot = 0;
while (m--) {
int p, q, t;
cin >> p >> q >> t;
add(q, p, t);
}
dijkstra(s);
cin >> w;
while (w--) {
int a;
cin >> a;
ans = min(ans, d[a]);
}
if (ans == INF) cout << -1 << endl;
else cout << ans << endl;
}
return 0;
}
思路二.
我们可以建立一个虚拟源点,使其到每个起始点的距离变为0,最短路由这个虚拟源点开始,变为一对一的问题。
因为这样第一个进入优先队列的是这个虚拟源点,与它相邻的只有所有的起始点,且一定会松弛为0,
因此在效果上就等于把所有的起始点压入优先队列中。
// 虚拟源点 + dijkstra
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int N = 1010,M = 2 * 20010;
int head[N], ver[M], edge[M], ne[M], d[N];
bool v[N];
int n, m, s, w, tot;
priority_queue<pair <int, int> >q;
void add (int x, int y, int z) {
ver[++tot] = y, edge[tot] = z, ne[tot] = head[x], head[x] = tot;
}
int dijkstra () {
memset(d, 0x3f, sizeof d);
memset(v, 0, sizeof v);
d[0] = 0;
q.push(make_pair(0, 0));
while (q.size()) {
int x = q.top().second; q.pop();
if (v[x]) continue;
v[x] = 1;
for (int i = head[x]; i; i = ne[i]) {
int y = ver[i], z = edge[i];
if (d[y] > d[x] + z) {
d[y] = d[x] + z;
q.push(make_pair(-d[y], y));
}
}
}
if (d[s] == INF) return -1;
else return d[s];
}
int main () {
while (cin >> n >> m >> s) {
memset(head, -1, sizeof head);
tot = 0;
while (m--) {
int p, q, t;
cin >> p >> q >> t;
add(p, q, t);
}
cin >> w;
while (w--) {
int a;
cin >> a;
add(0, a, 0);
}
cout << dijkstra() << endl;
}
return 0;
}
//把所有起始点压进有限队列 + dijkstra
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int N = 1010,M = 2 * 20010;
int head[N], ver[M], edge[M], ne[M], d[N];
bool v[N];
int n, m, s, w, tot;
priority_queue<pair <int, int> >q;
void add (int x, int y, int z) {
ver[++tot] = y, edge[tot] = z, ne[tot] = head[x], head[x] = tot;
}
int dijkstra () {
while (q.size()) {
int x = q.top().second; q.pop();
if (v[x]) continue;
v[x] = 1;
for (int i = head[x]; i; i = ne[i]) {
int y = ver[i], z = edge[i];
if (d[y] > d[x] + z) {
d[y] = d[x] + z;
q.push(make_pair(-d[y], y));
}
}
}
if (d[s] == INF) return -1;
else return d[s];
}
int main() {
while (cin >> n >> m >> s) {
memset(head, -1, sizeof head);
memset(d, 0x3f, sizeof d);
memset(v, 0, sizeof v);
tot = 0;
while (m--) {
int p, q, t;
cin >> p >> q >> t;
add(p, q, t);
}
cin >> w;
while (w--) {
int a;
cin >> a;
q.push(make_pair(0, a));
d[a] = 0;
}
cout << dijkstra() << endl;
}
return 0;
}
这里需要把d的初始化从dij函数中拉出来到main的循环里。
(感觉dijkstra码量和spfa差不多,没有负权我一般都用堆优化dij)
要记住初始化:
对于d[], v[], head[], tot 的初始化
本文作者:misasteria
本文链接:https://www.cnblogs.com/misasteria/p/16168716.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步