灾后重建

 

题面

给出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
");
37         } else {
38             if (f[u][v] == 0x3f3f3f3f) {
39                 printf("-1
");
40             } else {
41                 printf("%d
", f[u][v]);
42             }
43         }
44     }
45     return 0;
46 }
View Code
原文地址:https://www.cnblogs.com/Accpted/p/11185722.html