【洛谷P1119】灾后重建

题目大意:给定一个 N 个顶点,M 条边的无向图,每个顶点有一个时间戳,且时间戳大小按照顶点下标大小依次递增,在给定时间 t 时,时间戳严格大于 t 的顶点不能被访问,现在有 Q 次询问,每次询问在给定时间下,任意两个点的最短路是多少,若有点不能被访问,则输出 -1。

题解:因为 N<=200,且询问的是任意两点的最短路问题,所以考虑 Floyd 算法。在 Floyd 算法中,问题的阶段是经过前几个顶点,这句话也可以理解为:只经过前几个顶点的任意两点的最短路是多少。而这正好符合时间戳的概念,即:在某个阶段时,大于某一时间戳上限的点不会被访问到。因此,可以预处理出各个阶段,询问的时候直接查找询问时间所在的区间即可。

代码如下

#include <bits/stdc++.h>
using namespace std;
const int maxn=210;
const int inf=0x3f3f3f3f;

inline int read(){
    int x=0,f=1;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
    do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
    return f*x;
}

int n,m,t[maxn],d[maxn][maxn][maxn];

void read_and_parse(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)t[i]=read();

    memset(d,0x3f,sizeof(d));
    for(int i=1;i<=n;i++)d[0][i][i]=0;
    for(int i=1,x,y,z;i<=m;i++){
        x=read()+1,y=read()+1,z=read();
        d[0][x][y]=d[0][y][x]=min(d[0][x][y],z);
    }
}

void floyd(){
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                d[k][i][j]=min(d[k-1][i][j],d[k-1][i][k]+d[k-1][k][j]);
}

void solve(){
    floyd();
    int q=read();
    while(q--){
        int x=read()+1,y=read()+1,z=read();
        int idx=upper_bound(t+1,t+n+1,z)-t-1;
        printf("%d\n",t[x]<=z&&t[y]<=z&&d[idx][x][y]!=inf?d[idx][x][y]:-1);
    }
}

int main(){
    read_and_parse();
    solve();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wzj-xhjbk/p/10235344.html