题目大意:
题目链接:https://www.luogu.org/problemnew/show/P1119
地区在地震过后,所有村庄都造成了一定的损毁,而这场地震却没对公路造成什么影响。但是在村庄重建好之前,所有与未重建完成的村庄的公路均无法通车。换句话说,只有连接着两个重建完成的村庄的公路才能通车,只能到达重建完成的村庄。
给出B地区的村庄数N,村庄编号从到,和所有条公路的长度,公路是双向的。并给出第个村庄重建完成的时间,你可以认为是同时开始重建并在第天重建完成,并且在当天即可通车。若为则说明地震未对此地区造成损坏,一开始就可以通车。之后有个询问,对于每个询问你要回答在第天,从村庄到村庄的最短路径长度为多少。如果无法找到从村庄到村庄的路径,经过若干个已重建完成的村庄,或者村庄或村庄在第天仍未重建完成 ,则需要返回。
思路:
的用处真是太神了orz
表示枚举可以在限定时间范围内的修通路的点。由于保证了时间递增,直接每次即可。
然后就可以把时间压缩到
代码:
#include <cstdio>
#include <cstring>
#define N 210
using namespace std;
int n,m,tim[N],dis[N][N],t,x,y,z,k;
int main()
{
scanf("%d%d",&n,&m);
memset(dis,0x3f3f3f3f,sizeof(dis));
for (int i=1;i<=n;i++)
scanf("%d",&tim[i]); //time是保留字,不可以使用
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
x++;
y++;
dis[x][y]=z;
dis[y][x]=z;
}
scanf("%d",&t);
while (t--)
{
scanf("%d%d%d",&x,&y,&z);
x++;
y++;
for (;k<=n&&tim[k]<=z;k++) //这里减少了一重循环,因为保证了单调
{
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (i!=j&&j!=k&&k!=i)
if (dis[i][j]>(long long)dis[i][k]+dis[j][k])
dis[i][j]=dis[i][k]+dis[k][j];
}
if (dis[x][y]<0x3f3f3f3f&&tim[x]<=z&&tim[y]<=z) printf("%d\n",dis[x][y]);
else printf("-1\n");
}
return 0;
}