题目大意:
题目链接:https://www.luogu.org/problemnew/show/P1119
B
B
B地区在地震过后,所有村庄都造成了一定的损毁,而这场地震却没对公路造成什么影响。但是在村庄重建好之前,所有与未重建完成的村庄的公路均无法通车。换句话说,只有连接着两个重建完成的村庄的公路才能通车,只能到达重建完成的村庄。
给出B地区的村庄数N,村庄编号从
0
0
0到
N
−
1
N-1
N−1,和所有
M
M
M条公路的长度,公路是双向的。并给出第
i
i
i个村庄重建完成的时间
t
[
i
]
t[i]
t[i],你可以认为是同时开始重建并在第
t
[
i
]
t[i]
t[i]天重建完成,并且在当天即可通车。若
t
[
i
]
t[i]
t[i]为
0
0
0则说明地震未对此地区造成损坏,一开始就可以通车。之后有
Q
Q
Q个询问
(
x
,
y
,
t
)
(x, y, t)
(x,y,t),对于每个询问你要回答在第
t
t
t天,从村庄
x
x
x到村庄
y
y
y的最短路径长度为多少。如果无法找到从
x
x
x村庄到
y
y
y村庄的路径,经过若干个已重建完成的村庄,或者村庄
x
x
x或村庄
y
y
y在第
t
t
t天仍未重建完成 ,则需要返回
−
1
-1
−1。
思路:
F
l
o
y
d
Floyd
Floyd的用处真是太神了orz
k
k
k表示枚举可以在限定时间范围内的修通路的点。由于保证了时间递增,直接每次
k
+
+
k++
k++即可。
然后就可以把时间压缩到
O
(
n
3
+
q
)
O(n^3+q)
O(n3+q)
代码:
#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;
}