道路与航线
原题链接
题目描述
农夫约翰正在一个新的销售区域对他的牛奶销售方案进行调查。
他想把牛奶送到 \(T\) 个城镇,编号为 \(1\)∼\(T\)。
这些城镇之间通过 \(R\) 条道路 (编号为 \(1\) 到 \(R\)) 和 \(P\) 条航线 (编号为 \(1\) 到 \(P\)) 连接。
每条道路 \(i\) 或者航线 \(i\) 连接城镇 \(A_i\) 到 \(B_i\),花费为 \(C_i\)。
对于道路,\(0≤C_i≤10,000\);然而航线的花费很神奇,花费 \(C_i\) 可能是负数\((−10,000≤C_i≤10,000)\)。
道路是双向的,可以从 \(A_i\) 到 \(B_i\),也可以从 \(B_i\) 到 \(A_i\),花费都是 \(C_i\)。
然而航线与之不同,只可以从 \(A_i\) 到 \(B_i\)。
事实上,由于最近恐怖主义太嚣张,为了社会和谐,出台了一些政策:保证如果有一条航线可以从 \(A_i\) 到 \(B_i\),那么保证不可能通过一些道路和航线从 \(B_i\) 回到 \(A_i\)。
由于约翰的奶牛世界公认十分给力,他需要运送奶牛到每一个城镇。
他想找到从发送中心城镇 \(S\) 把奶牛送到每个城镇的最便宜的方案。
思路 拓扑排序+Dijkstra
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 | #include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int N = 25010, M = 150010;
const int inf = 0x3f3f3f3f;
int n, mr, mp, S, bcnt;
int h[N], e[M], w[M], ne[M], idx;
int dist[N], din[N], id[N];
bool st[N];
vector<int> block[N];
queue<int> q;
void add(int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u, int bid) {
id[u] = bid;
block[bid].push_back(u);
for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
if (!id[j])
dfs(j, bid);
}
}
void dijkstra(int bid) {
priority_queue<PII, vector<PII>, greater<PII>> heap;
for (int u : block[bid]) heap.push({dist[u], u});
while (heap.size()) {
auto [distence, ver] = heap.top();
heap.pop();
if (st[ver]) continue;
st[ver] = true;
for (int i = h[ver]; i != -1; i = ne[i]) {
int j = e[i];
if (dist[j] > distence + w[i]) {
dist[j] = distence + w[i];
if (id[ver] == id[j]) heap.push({dist[j], j});
}
if (id[j] != id[ver]) {
din[id[j]]--;
if (din[id[j]] == 0) q.push(id[j]);
}
}
}
}
void topsort() {
memset(dist, 0x3f, sizeof dist);
dist[S] = 0;
for (int i = 1; i <= bcnt; i++)
if (!din[i])
q.push(i);
while (q.size()) {
int t = q.front();
q.pop();
// 连通块跑Dijkstra
dijkstra(t);
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
memset(h, -1, sizeof h);
cin >> n >> mr >> mp >> S;
while (mr--) {
int a, b, c;
cin >> a >> b >>c;
add(a, b, c);
add(b, a, c);
}
// 求连通块
for (int i = 1; i <= n; i++)
if (!id[i])
dfs(i, ++bcnt);
while (mp--) {
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
din[id[b]]++;
}
topsort();
for (int i = 1; i <= n; i++)
cout << (dist[i] > inf / 2 ? "NO PATH" : to_string(dist[i])) << endl;
return 0;
}
|