看n那么小,刚开始我就想暴力dijkstra,结果O(Qnlogn)光荣TLE,竟得了80分……
正解是floyd。
考虑朴素的floyd,dis[i][j]表示 i 到 j 的最短路,然而最原始的是dis[k][i][j],以前k个点为中继点时 i 到 j 的最短路,于是有dis[k][i][j] = min(dis[i][j], dis[k - 1][i][k] + dis[k - 1][k][j])。然后为了空间把第一维优化掉了。
那么这道题也同理,dis[k][i][j]表示k时刻 i 到 j 的最短路,然后我们边查询边更新,因为查询时间保证递增,所以对于每一次查询,枚举上一次查询到这一次查询的时间中所有的点作为中继点,然后O(n2)更新多源最短路。
总复杂度O(n3 + Q)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16 typedef long long ll; 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const db eps = 1e-8; 20 const int maxn = 2e2 + 5; 21 inline ll read() 22 { 23 ll ans = 0; 24 char ch = getchar(), last = ' '; 25 while(!isdigit(ch)) last = ch, ch = getchar(); 26 while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar(); 27 if(last == '-') ans = -ans; 28 return ans; 29 } 30 inline void write(ll x) 31 { 32 if(x < 0) x = -x, putchar('-'); 33 if(x >= 10) write(x / 10); 34 putchar(x % 10 + '0'); 35 } 36 37 int n, m, t[maxn]; 38 int dis[maxn][maxn]; 39 40 int main() 41 { 42 n = read(); m = read(); 43 Mem(dis, 0x3f); 44 for(int i = 0; i < n; ++i) t[i] = read(), dis[i][i] = 0; 45 for(int i = 1; i <= m; ++i) 46 { 47 int x = read(), y = read(), w = read(); 48 dis[x][y] = dis[y][x] = w; 49 } 50 int q = read(); 51 for(int h = 1, k = 0; h <= q; ++h) 52 { 53 int x = read(), y = read(), tim = read(); 54 while(t[k] <= tim && k < n) 55 { 56 for(int i = 0; i < n; ++i) 57 for(int j = 0; j < n; ++j) 58 dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]); 59 k++; 60 } 61 if(dis[x][y] == INF || t[x] > tim || t[y] > tim) write(-1), enter; 62 else write(dis[x][y]), enter; 63 } 64 return 0; 65 }