洛谷P1119 灾后重建 图论 脑洞题

洛谷P1119 灾后重建

图论   脑洞题   floyd   
floyd中 k 的意义 通过前 k 个点 作为中间的节点 更新 i 到 j 的最短路 也就是 只经过前 k 个点 的最短路


帮助理解Floyd算法的好题!初学Floyd算法时,相信很多人和我一样,只是把几行代码背下来,
并没有了解Floyd算法到底是什么原理。以下介绍Floyd算法的原理:

Floyd算法的本质是动态规划,其转移方程为:f(k,i,j) = min( f(k-1,i,j), f(k-1,i,k)+f(k-1,k,j) )。

f(k,i,j)表示路径除开起点i与终点j,只经过前k个点中的某些点,从i到j的最小值。计算这个值只需要考虑两种情况:
最短路经过k,和最短路不经过k(那么就经过前k-1个点中的某些点)。由于k要从k-1转移而来,自然k为最外层的循环。
而经过状态压缩(类似于背包问题)后,就变成了我们熟悉的f(i,j) = min( f(i,j), f(i,k)+f(k,j) )了。

本题同理,只是k表示的是最先修好的前k个村庄。不过由于出题人非常良心地帮我们把修理时间和询问时间都排序了,
所以就没什么关系了- -用Floyd枚举k时,枚举到下一个询问的时间点就停止。回答询问之后,再继续枚举。

 1 #include <cstdio>
 2 #include <cmath>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <string>
 6 #include <iostream>
 7 #include <iomanip>
 8 using namespace std ; 
 9 
10 const int maxn = 211,maxq = 50011,inf = 1e9 ; 
11 int n,m,Q,now ; 
12 int e[maxn][maxn],t[maxn] ; 
13 int tq[maxq],qs[maxq],qt[maxq] ; 
14 
15 inline int read() 
16 {
17     char ch = getchar() ; 
18     int x = 0 , f = 1 ; 
19     while(ch<'0'||ch>'9') { if( ch=='-' ) f = -1 ; ch = getchar() ; } 
20     while(ch>='0'&&ch<='9') { x = x*10 + ch - 48 ; ch = getchar() ; } 
21     return x * f ; 
22 }
23 
24 inline int print(int now) 
25 {
26     if( t[ qs[now] ] > tq[ now ] || t[ qt[now] ] > tq[ now ] ) 
27         return -1 ; 
28     if( e[qs[now]][qt[now]]==inf ) 
29         return -1 ; 
30     return e[qs[now]][qt[now]] ;  
31 }
32 
33 int main() 
34 {
35     n = read() ; m = read() ; 
36     for(int i=0;i<n;i++) t[ i ] = read() ; 
37     for(int i=0;i<n;i++) 
38         for(int j=0;j<n;j++) e[ i ][ j ] = inf ; 
39         
40     
41     int x,y,v ; 
42     for(int i=1;i<=m;i++) 
43     {
44         x = read() ; y = read() ; v = read() ; 
45         e[ x ][ y ] = v ; e[ y ][ x ] = v ; 
46     }
47     
48     Q = read() ;  
49     for(int i=1;i<=Q;i++) 
50     {
51         qs[ i ] = read() ; qt[ i ] = read() ; tq[ i ] = read() ;   
52     }
53     
54     now = 1 ; 
55     for(int k=0;k<n;k++) 
56     {
57         while( now <= Q && tq[now] < t[ k ] )    // 这样相当于做询问 Q 是 就已经将 在他之前的 边考虑到
58                                                 //询问的时间小于当前时间则输出 
59         {
60             printf("%d
",print( now ) ) ; 
61             now++ ; 
62         }
63         for(int i=0;i<n;i++) 
64             for(int j=0;j<n;j++) 
65                 e[ i ][ j ] = min(e[ i ][ j ],e[ i ][ k ] + e[ k ][ j ]) ; 
66     }
67     
68     while( now<=Q ) 
69     {
70         printf("%d
",print(now)) ; 
71         now++ ; 
72     }
73      
74     return 0 ; 
75 }
原文地址:https://www.cnblogs.com/third2333/p/7097440.html