询问x到y的距离,首先想到Flody方法,但是题目中,给定了最短路上,不能有城镇建好的时间超过 ti 的,因此,如果对每一次询问都跑一边Floyd,那么肯定会超时。因此我们需要更好的思路,Floyd的是基于动态规划实现的最短路算法,转移方程为
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
表示i点到j点的路径,可以用i到k,k到j点路径来松弛,因此,我们可以发现,当i,j,k 节点都在 ti 时间内建好的话,那么这个松弛是有效的,因此我们枚举过程中,控制 k 点在时间 t 内建造完成,因为节点的建造完成时间是按升序给的,因此我们每次做Floyd都只需要从当前的k值,枚举到在 ti 时间内的 k 值就行,之前所枚举的状态会被记录,而T总体是升序的,因此时间复杂度为 O(n^3)
代码如下
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> Pi;
typedef unsigned long long ULL;
int gcd(int a,int b){if (b == 0) return a; return gcd(b , a%b);}
int lcm(int a, int b){ return a/gcd(a,b)*b;}
inline int read(){
int f = 1, x = 0;char ch = getchar();
while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
return x * f;
}
const int maxn = 1e4 + 10;
int n,m;
int t[maxn];
int dis[maxn][maxn],G[maxn][maxn];
int main(){
n = read(); m = read();
for(int i=0; i<n; i++){
t[i] = read();
}
for(int i=0; i<n; i++){
for(int j=0; j<n; j++){
dis[i][j] = i == j ? 0 : 1e9;
}
}
for(int i=0 ;i<m; i++){
int u = read(),v = read(),w = read();
dis[u][v] = dis[v][u] = w;
}
int q = read(),k = 0;
while(q--){
int x = read(),y = read(),t0 = read();
for(; k<n && t[k] <= t0; k++){
for(int i=0; i<n; i++){
for(int j=0; j<n; j++){
dis[i][j] = min(dis[i][j],dis[i][k] + dis[k][j]);
}
}
}
if (t[x] > t0 || t[y] > t0 || dis[x][y] == 1e9){
printf("-1\n");
}else{
printf("%d\n",dis[x][y]);
}
}
return 0;
}