洛谷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;
}

posted @ 2021-02-07 13:32  牟翔宇  阅读(57)  评论(0编辑  收藏  举报