【题解】P1119 灾后重建

题目链接(洛谷)

题目大意

有$n$个村庄,编号从$0$~$n−1$。给出$m$条双向公路连接这些村庄。

发生了一次地震,对所有村庄造成了一些损毁,但对公路没有影响。

现在要重建村庄,给出第$i$个村庄重建完成的时间$t_i$。之后又$Q$个询问$(x,y,t)$,对于每个询问。你要回答在第$t$天,从村庄$x$到村庄$y$的最短路长度为多少。如果无法找到路径或者$x,y$没有重建完成,输出$−1$。

$N\le 200,M\le \frac{N\times (N-1)}{2}, Q\le 50000$

分析

所有的边已经给出,按照时间顺序更新每一个可用的点,求对于目前建设的村庄来说任意两点之间的最短路。

正是Floyd算法的使用前$k$个点更新最短路的思路。

实现

$(100pts,409ms,764.00kb)$

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
#include<bits/stdc++.h>

using namespace std;
const int N = 205, M = 400005;
int n, m, q;
int t[N], f[N][N], x, y, z;

void update(int k) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (f[i][j] > f[i][k] + f[j][k]) {
f[i][j] = f[j][i] = f[i][k] + f[j][k];
}
}
}
}

int main() {
cin >> n >> m;
for (int i = 0; i < n; i++) {
cin >> t[i];
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
f[i][j] = 0x3f3f3f3f;
}
}
for (int i = 0; i < n; i++) {
f[i][i] = 0;
}
for (int i = 0; i < m; i++) {
cin >> x >> y >> z;
f[x][y] = z;
f[y][x] = z;
}
cin >> q;
int cur = 0;
while (q--) {
cin >> x >> y >> z;
while (t[cur] <= z && cur < n) {
update(cur);
cur++;
}
if (t[x] > z || t[y] > z) cout << -1 << endl;
else {
if (f[x][y] == 0x3f3f3f3f) cout << -1 << endl;
else cout << f[x][y] << endl;
}

}
return 0;
}