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 的初始化