题目
题解
由于询问数Q比较大,不可能每次询问都新建图,所以考虑离线(集中处理询问)。注意到村庄重建时间是不严格递增的,所以在时间t[i]之前,只有编号为0~i的村庄重建完。注意到村庄数n比较小,可以考虑floyd算法,这个算法可以求出任意两点间的最短路,同时,在动态规划过程中,floyd算法也解决了“若只经过编号为0~i的节点,求任意两点间的最短路径”这个子问题。所以,在执行floyd算法的同时,更新符合当前条件的询问的答案。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=200+5;
const int maxq=5e4+5;
int n,m,q;
int d[maxn][maxn],ti[maxn];
struct question{int x,y,t,ans;}a[maxq];
inline void floyd()
{
for(int i=0;i<n;i++) d[i][i]=0;
for(int k=0;k<n;k++)
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
for(int i=q;i>=1&&ti[k]<=a[i].t;i--)
if(a[i].x<=k&&a[i].y<=k) a[i].ans=min(a[i].ans,d[a[i].x][a[i].y]);
} //注意floyd算法在第k轮求出的d[][],并不能保证路径的起点和终点属于编号为0~k的节点
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++) scanf("%d",&ti[i]);
memset(d,0x3f,sizeof(d));
for(int i=1;i<=m;i++)
{
int x,y,z; scanf("%d%d%d",&x,&y,&z);
d[x][y]=d[y][x]=z;
}
scanf("%d",&q);
for(int i=1;i<=q;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].t),a[i].ans=inf;
floyd();
for(int i=1;i<=q;i++)
{
if(a[i].ans==inf) printf("-1\n");
else printf("%d\n",a[i].ans);
}
return 0;
}