题面:
给你一个 $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;
}
标签:cnt,val,int,题解,Quickly,vis,edge,Come,dis
From: https://www.cnblogs.com/PerchLootie/p/18237788