P1119 灾后重建
题目链接:P1119
题目大意:
有点复杂,略了,大概就是有Q次询问,每次询问在有些道路不能走的情况下,给定的两个村庄的最短路。
解题思路:
为什么说是好题?因为明白了不是所有的非负权图最短路,dijkstra都合适。看完题目,首先想到DJ算法,但是忽略了复杂度,DJ复杂度mlogn,q次询问就是qmlogn,大概时1e9+常数,没错会T。虽然Floyd是n³,但是因为这个题的特殊(或者说是巧妙),可以把最外层循环放在每次询问里,这样总的复杂度大概也是n³。
Floyd思想就是,每次只允许经过k个点时,图中两点之间的最短距离是多少,其中
f[i][j] = min(f[i][j], f[i][k]+f[k][j]); 有迪屁的思想。
根据Floyd还可求正权无向图的最小权值环,以及图的传递闭包。
参考代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <queue> 6 #include <stack> 7 #include <vector> 8 #include <algorithm> 9 #define N 2010 10 using namespace std; 11 const int MAX = 1061109567; // memset(f,0x3f,sizeof(f))后元素的值 12 int f[N][N],t[N]; // 邻接矩阵存图 13 14 inline int read() 15 { 16 int x = 0, y = 1; char c = getchar(); 17 while(c < '0' || c > '9') {if(c == '-') y = -1; c = getchar();} 18 while(c >= '0' && c <= '9') x = x*10+c-'0', c = getchar(); 19 return x*y; 20 } 21 // 初始化 22 void init() 23 { 24 memset(f,0x3f,sizeof(f)); 25 for(int i = 0; i < N; i++) 26 for(int j = 0; j < N; j++) 27 if(i == j) 28 f[i][j] = 0; 29 } 30 31 int main() 32 { 33 init(); 34 int k = 0; 35 int n,m,q; 36 int u,v,wi; 37 int x,y,ti; 38 n = read(); 39 m = read(); 40 for(int i = 0; i < n; i++) 41 t[i] = read(); 42 for(int i = 0; i < m; i++) 43 { 44 u = read(); 45 v = read(); 46 wi = read(); 47 f[u][v] = f[v][u] = wi; // 双向边 48 } 49 q = read(); 50 while(q--) 51 { 52 x = read(); 53 y = read(); 54 ti = read(); 55 if(t[x] > ti || t[y] > ti) // 感觉这个判断放在前面,有些数据是可以很节省时间的 56 { 57 printf("-1\n"); 58 continue; 59 } 60 while(t[k] <= ti && k < n) 61 { 62 for(int i = 0; i < n; i++) 63 for(int j = 0; j < n; j++) 64 f[i][j] = f[j][i] = min(f[i][j],f[i][k]+f[k][j]);// Floyd的核心 65 k++; 66 } 67 if(f[x][y] == MAX) printf("-1\n"); 68 else printf("%d\n",f[x][y]); 69 } 70 return 0; 71 }

浙公网安备 33010602011771号