灾后重建
题面
给出B地区的村庄数N,村庄编号从0到N-1,和所有M条公路的长度,公路是双向的。并给出第i个村庄重建完成的时间ti,你可以认为是同时开始重建并在第ti天重建完成,并且在当天即可通车。若ti为则说明地震未对此地区造成损坏,一开始就可以通车。之后有Q个询问(x,y,t),对于每个询问你要回答在第t天,从村庄x到村庄y的最短路径长度为多少。如果无法找到从x村庄到y村庄的路径,经过若干个已重建完成的村庄,或者村庄x或村庄y在第t天仍未重建完成 ,则需要返回-1。
思路:
Floyd的理解
for (int k=0;k<n;k++)
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if (f[i][j] > f[i][k] + f[k][j])
f[i][j] = f[j][i] = f[i][k] + f[k][j];
这段代码的基本思想就是:最开始只允许经过1号顶点进行中转,接下来只允许经过1和2号顶点进行中转……允许经过1~n号所有顶点进行中转,求任意两点之间的最短路程。用一句话概括就是:从i号顶点到j号顶点只经过前k号点的最短路程。
(仔细理解这段话,它揭露了这个算法的本质并为本题提供了很好的方法)
到这里我们已经知道,Floyd算法就是一个利用其它点进行中转来求最短路的步骤。
而我们再回头看题意:
所有的边全部给出,按照时间顺序更新每一个可用的点(即修建好村庄),对于每个时间点进行两点之间询问,求对于目前建设的所有村庄来说任意两点之间的最短路
不正好就是Floyd算法中使用前k个节点更新最短路的思维吗?
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=210; 4 int a[N],f[N][N],n,m,q,k,u,v,w,t; 5 void fun(int k) { 6 for (int i = 0; i < n; i++) { 7 for (int j = 0; j < n; j++) { 8 if (f[i][j] > f[i][k] + f[k][j]) { 9 f[i][j] = f[j][i] = f[i][k] + f[k][j]; 10 } 11 } 12 } 13 } 14 int main() { 15 scanf("%d%d", &n, &m); 16 for (int i = 0; i < n; i++) { 17 scanf("%d", &a[i]); 18 } 19 memset(f, 0x3f3f3f3f, sizeof(f)); 20 for (int i = 0; i < n; i++) { 21 f[i][i] = 0; 22 } 23 for (int i = 1; i <= m; i++) { 24 int u, v, w; 25 scanf("%d%d%d", &u, &v, &w); 26 f[u][v] = f[v][u] = w; 27 } 28 scanf("%d", &q); 29 while (q--) { 30 scanf("%d%d%d", &u, &v, &t); 31 while (a[k] <= t && k < n) { 32 fun(k); 33 k++; 34 } 35 if (a[u] > t || a[v] > t) { 36 printf("-1\n"); 37 } else { 38 if (f[u][v] == 0x3f3f3f3f) { 39 printf("-1\n"); 40 } else { 41 printf("%d\n", f[u][v]); 42 } 43 } 44 } 45 return 0; 46 }