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