[ABC191E] Come Back Quickly 题解

题面:

给你一个 \(n\) 个点 \(m\) 条边的有向图,第 \(i\) 条边 \(a_i\)\(b_i\)\(c_i\),表示一条单向边从 \(a_i\) 到 $ b_i$,长度为 \(c_i\),可能会有重边和自环。问能否从第 \(i\) 号点出发然后回到该点形成一个环?可以则输出最短时间,否则输出 \(-1\)

思路:

不难发现本题考查的是最短路。
观察题面,发现边数与点数都较大,考虑堆优化 Dijkstra,对于每个点 \(i\) 都跑一次堆优化 Dijkstra,在确定最初进行松弛的点时将点 \(i\) 的邻接点放入堆即可。如连通,最后的答案即为 \(dis_i\),否则为 \(-1\)

#include<bits/stdc++.h>
using namespace std;
int a,s,d[100005],f;
int ans;
int head[100005],cnt=1;
int dis[100005];
int vis[100005];
struct jntm{
    int to,next,val;
}edge[100005];
struct node{
    int qz,bh;
    bool operator>(const node& x)const{
        return qz>x.qz;
    }
};
priority_queue<node,vector<node>,greater<node> > q;
void add(int x,int y,int z){
    edge[cnt].to=y;
    edge[cnt].next=head[x];
    edge[cnt].val=z;
    head[x]=cnt++;
}
int dij(int x){
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    while(q.size()){
        q.pop();
    }
    for(int i=head[x];i;i=edge[i].next){
        int y=edge[i].to;
        dis[y]=min(dis[y],edge[i].val);
        q.push(node{dis[y],y});
    }
    while(q.size()){
        int u=q.top().bh;
        q.pop();
        if(vis[u]){
            continue;
        }
        vis[u]=1;
        for(int i=head[u];i;i=edge[i].next){
            int y=edge[i].to;
            if(dis[y]>dis[u]+edge[i].val){
                dis[y]=dis[u]+edge[i].val;
            }
            q.push(node{dis[y],y});
        }
    }
    return dis[x]==dis[0]?-1:dis[x];
}
int main(){
    scanf("%d%d",&a,&s);
    for(int i=1;i<=s;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
    }
    for(int i=1;i<=a;i++){
        printf("%d\n",dij(i));
    }
    return 0;
}
posted @ 2024-06-07 19:49  Rannio  阅读(18)  评论(0)    收藏  举报