题目大意:村庄受损道路完好。
给出B地区的村庄数N,村庄编号从0到N-1,和所有M条公路的长度,公路是双向的。并给出第i个村庄重建完成的时间t[i],你可以认为是同时开始重建并在第t[i]天重建完成,并且在当天即可通车。若t[i]为0则说明地震未对此地区造成损坏,一开始就可以通车。之后有Q个询问(x, y, t),对于每个询问你要回答在第t天,从村庄x到村庄y的最短路径长度为多少。如果无法找到从x村庄到y村庄的路径,经过若干个已重建完成的村庄,或者村庄x或村庄y在第t天仍未重建完成 ,则需要返回-1。
这道题与常见的灾后重建有类似又有不同:常见的灾后重建是村庄完好重建道路,往往是跑最短路或最小生成树的模板,但此题是村庄受损道路完好,想到与点关系密切的最短路算法就只有floyd.再看这道题的N只有200,更加肯定了是floyd。
思路是:对于每个询问,去依次枚举这个询问前恢复了的每个点。
这题和Floyd模板不同的是用了2个数组,g[][]和dis[][]来跑floyd,因为对于每个询问,恢复的点都不同,dis[a][b]表示当前这个询问时a到b的最短路程,而g[a][b]表示若所有点都可用时a到b的最短路程。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 100;
const int inf = 0x3f3f3f3f;
int dis[202][202],t[202],n,m,q,x,y,ti,a,b,w,g[202][202];
int main()
{
memset(dis,inf,sizeof(dis));
memset(g,inf,sizeof(g));
scanf("%d%d",&n,&m);
for(int i = 0; i < n; ++i) scanf("%d",&t[i]);
for(int i = 1; i <= m; ++i)
{
scanf("%d%d%d",&a,&b,&w);
g[a][b] = g[b][a] = w;
}
sort(t, t + n);
for(int i = 0; i < n; ++i) g[i][i] = 0;
scanf("%d",&q);
for(int i = 1,j = 0; i <= q; ++i)
{
scanf("%d%d%d",&x,&y,&ti);
while(t[j] <= ti && j < n)
{
for(int a = 0; a < n; ++a)
for(int b = 0; b < n; ++b)
if(a != b)
{
g[a][b] = min(g[a][b],g[a][j] + g[j][b]);
if(t[a] <= ti && t[b] <= ti)
{
dis[a][j] = min(g[a][j],dis[a][j]);dis[j][b] = min(dis[j][b],g[j][b]);
dis[a][b] = min(dis[a][b],dis[a][j] + dis[j][b]);
}
}
++j;
}
if(dis[x][y] == inf) printf("-1\n");
else printf("%d\n",dis[x][y]);
}
return 0;
}