来源:JZOJ,Luogu P1119 灾后重建
题目描述-原题
B B B地区在地震过后,所有村庄都造成了一定的损毁,而这场地震却没对公路造成什么影响。但是在村庄重建好之前,所有与未重建完成的村庄的公路均无法通车。换句话说,只有连接着两个重建完成的村庄的公路才能通车,只能到达重建完成的村庄。
改版
疫情导致很多城市的公路都封掉了。
现在疫情开始没那么严峻, z j zj zj 省的高速公路开始慢慢恢复。
现在设 z j zj zj 省的城市有 N N N 个,有 M M M 条双向公路相连,每条公路有相应的长度。
现在给出第 i i i 个城市公路开通的时间 t [ i ] t[i] t[i]。
当然如果 t [ i ] t[i] t[i] 为 0 0 0,表示第i个城市就没有封锁。
现在指挥部要知道道路运行情况,有 S S S 次询问,询问格式为 ( s t , e n , q ) (st,en,q) (st,en,q)
每个询问表示从 s t st st 号城市到 e n en en 城市,在第 q q q 天是否可以到达,如果可以到达,请给出最短的长度,如果不可以到达,输出 − 1 -1 −1。
解题思路
- 这是一道深入 F l o y d Floyd Floyd 本质的题目,首先得先了解一下 F l o y d Floyd Floyd,这短小精悍的算法:通过其他中转点求任意两点之间的最短路,丢代码;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
- 这段代码能否和本题联系起来呢?
- 思路如下:按时间顺序找到每一个在 q q q天之内能修好的点,作为中转点,暴力 F l o y d Floyd Floyd 即可
- 不过,这样是会 T L E TLE TLE 的,我们需要加一个小优化,就是用一个 v i s vis vis 数组标记, v i s [ i ] vis[i] vis[i] 表示 i i i 是否做过中转点,这样就可以 A C AC AC 了
C o d e Code Code
#pragma GCC optimize ("O2") //err... 手动开O2...罒ω罒
#pragma G++ optimize ("O2")
#include <bits/stdc++.h>
#define Inf 0x3fffffff
using namespace std;
bool vis[210];
int a[210][210],t[210];
inline int read() //快读
{
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
int main()
{
freopen("rebuild.in","r",stdin);
freopen("rebuild.out","w",stdout);
int n=read(),m=read();
for (register int i=0;i<n;i++) t[i]=read();
for (register int i=0;i<n;i++) //手动赋值正无穷(邻接矩阵)
for (register int j=0;j<n;j++)
a[i][j]=Inf;
for (register int i=0;i<n;i++) a[i][i]=0; //i点到i点距离为0
for (register int i=1;i<=m;i++)
{
int x=read(),y=read(),v=read();
a[x][y]=a[y][x]=v; //赋初值
}
int q;
q=read();
for (register int I=1;I<=q;I++) //q次询问
{
int st=read(),en=read(),time=read();
int k=0;
for (register int k=0;k<n;k++)
{
if (t[k]<=time && !vis[k]) //找到没有用过且在q天之内能修好的点
{
vis[k]=1; //标记
for (register int i=0;i<n;i++)
for (register int j=0;j<n;j++)
a[i][j]=min(a[i][j],a[i][k]+a[k][j]); //Floyd更新距离
}
}
if (t[st]>time || t[en]>time || a[st][en]>=Inf) printf("-1\n"); //不合法
else printf("%d\n",a[st][en]);
}
return 0;
}