洛谷P1119-灾后重建-floyd算法
洛谷P1119-灾后重建
题目描述
给出\(B\)地区的村庄数NN,村庄编号从\(0\)到\(N-1\),和所有\(M\)条公路的长度,公路是双向的。
给出第\(i\)个村庄重建完成的时间\(t_i\),你可以认为是同时开始重建并在第\(t_i\)天重建完成,并且在当天即可通车。若\(t_i=0\)则说明地震未对此地区造成损坏,一开始就可以通车。
之后有\(Q\)个询问\((x,y,t)\),对于每个询问你要回答在第\(t\)天,从村庄\(x\)到村庄\(y\)的最短路径长度为多少。如果无法找到从\(x\)村庄到\(y\)村庄的路径,经过若干个已重建完成的村庄,或者村庄\(x\)或村庄\(y\)在第\(t\)天仍未重建完成 ,则需要返回\(-1\)。
题解:
非常有意思的一道\(floyd\)题目。
题目保证村庄\(0\)到村庄\(N\)的修复时间满足\(t_0<t_1<...<t_{n-1}\),而且给出来询问中的\(t\)也是递增的。
那么我们回忆一下\(floyd\)算法的核心代码:
for (int k = 1; i <= N; k++)
for (int i = 1; i <= N; i++)
for (int j = 1; j <= N; j++)
f[i][j] = std::min(f[i][j], f[i][k] + f[k][j]);
这段代码的第一层枚举的\(k\)就是说允许\(k\)点进行中转。
现在题目给出了修建完毕需要的时间并且时间是递增的,给出的询问时间也是递增的,那么每次询问就用\(floyd\)将\(k\)枚举到最后一个村庄这个村庄有\(t_i <= t\),之后检查\(x,y\)点的\(t_x,t_y\)是否大于\(t\)以及\(f[x][y]\)是否为无穷大即可。
AC代码
#include <cstdio>
#include <cstring>
const int Maxn = 205;
const int INF = 0x3f3f3f3f;
int dis[Maxn][Maxn];
int Time[Maxn];
void update(int k, const int &nv) {
for (int i = 0; i < nv; i++) {
for (int j = 0; j < nv; j++) {
if (dis[i][j] > dis[i][k] + dis[k][j]) {
dis[i][j] = dis[i][k] + dis[k][j];
}
}
}
}
void solve() {
int nv, ne;
scanf("%d %d", &nv, &ne);
for (int i = 0; i < nv; i++) {
scanf("%d", Time + i);
}
int u, v, w;
memset(dis, INF, sizeof dis);
for (int i = 0; i < ne; i++) {
scanf("%d %d %d", &u, &v, &w);
dis[u][v] = dis[v][u] = w;
}
int nq, x, y, t, cur = 0;
scanf("%d", &nq);
for (int i = 0; i < nq; i++) {
scanf("%d %d %d", &x, &y, &t);
while (Time[cur] <= t && cur < nv) {
update(cur++, nv);
}
if (Time[x] > t || Time[y] > t || dis[x][y] == INF) {
printf("-1\n");
} else {
printf("%d\n", dis[x][y]);
}
}
}
int main() {
solve();
return 0;
}