P1119 灾后重建

89 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情

题意:给出 B 地区的村庄数 N,村庄编号从 0 到 N−1,和所有 M 条公路的长度,公路是双向的。并给出第 i 个村庄重建完成的时间 ti,你可以认为是同时开始重建并在第 ti 天重建完成,并且在当天即可通车。若 ti 为 0 则说明地震未对此地区造成损坏,一开始就可以通车。之后有 Q 个询问(x,y,t),对于每个询问你要回答在第 t 天,从村庄 x 到村庄 y 的最短路径长度为多少。如果无法找到从 x 村庄到 y 村庄的路径,经过若干个已重建完成的村庄,或者村庄 x 或村庄 y 在第 t 天仍未重建完成,则需要返回 -1
思路: floyd三重循环的第一重是有意义的,是i和j之间允许那几个点作为中转点以使i和j的距离能够更短,那这题不就很好的体现了这个吗,那个村庄建好了,那个就被允许作为中转点了,然后进行一遍转移,之后在看看x,y之间有没有最短的路径就行了

#include<bits/stdc++.h>
//#pragma-GCC-optimize("-Ofast");
#define ll long long
//#define int long long
#define lowbit(x) ((x)&(-x))
#define endl '\n'
using namespace std;
const ll mod=998244353;
const ll inf=1e9;
const double pi=acos(-1);
const int N=1e6+100;
ll qpow(ll a,ll b)
{
    ll res=1;
    while(b)
    {
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a){return qpow(a,mod-2);}
int n,m,t[205],g[205][205];
void floyd(int x){
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        g[i][j]=min(g[i][j],g[i][x]+g[x][j]);
}
signed main()
{
    //ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>t[i];
    for(int i=0;i<=n;i++)
    for(int j=0;j<=n;j++){
        g[i][j]=inf;
        if(i==j) g[i][j]=0;
    }
    for(int i=1;i<=m;i++){
        int u,v,w;cin>>u>>v>>w;
        u++;v++;
        g[u][v]=g[v][u]=w;
    }
    int q,cnt=1;cin>>q;
    while(q--){
        int x,y,ti;cin>>x>>y>>ti;
        x++;y++;
        while(t[cnt]<=ti&&cnt<=n){floyd(cnt);cnt++;}
        if(g[x][y]==inf||t[x]>ti||t[y]>ti) cout<<"-1\n";
        else cout<<g[x][y]<<endl;
    }
    return 0;
}