[ABC191E] Come Back Quickly 題解

PerchLootie發表於2024-06-07

題面:

給你一個 $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;
}

相關文章