经典单源最短路径算法之一,优点是速度比spfa快,缺点是不能处理负边权
简单的说核心思想就是 当前节点的最短路径上的节点的最短距离一定小于等于当前节点。
仔细理解一下核心语句!
流程
1.初始化,将起始点的最短距离设置为0,其他点的最短距离设置为无穷大,将所有点的标记设为false。将起始点放进队列。
2.找到队列里最短距离最小的节点(当然是第一次出队列,如果当前节点已经出过队列说明最小距离已经找过了),为了方便就称这个节点为 A。
3.先将A节点打上出过队列的标记,然后用A节点去更新A指向的节点的最短距离,如果A节点的最短距离加上路径边权要小于指向节点的最短距离的话,就要更新指向节点的最短距离了。
第二步中找最短距离最小的节点用的是优先队列,复杂度也就是log ,每个节点会跑一次所有与他相连的边,出队列的次数最多与相连的边数有关,所以时间复杂度也就是((V+E)logE).
#include<bits/stdc++.h>
#define fr first
#define sc second
#define pii pair<int,int>
#define pll pair<long,long>
#define rep(i,st,ed) for(int i=st;i<=ed;i++)
#define per(i,ed,st) for(int i=ed;i>=st;i--)
#define pb push_back
#define bp() pop_back();
#define dg(x) cout<<#x<<"="<<x<<endl;
#define dgg(x,y) cout<<#x<<"="<<x<<" "<<#y<<"="<<y<<endl;
#define dggg(x,y,z) cout<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl;
#define ppt(x) if(x)printf("YES\n");else{printf("NO\n");}
using namespace std;
const int N=1e6+5;
int n,m;
int last[N],tot;
struct Edge{
int u,v,next;
}a[N];
void add(int u,int v,int w){
a[++tot].u=v;
a[tot].v=w;
a[tot].next=last[u];
last[u]=tot;
}
struct Node{
int dis,pos;
bool operator < (const Node &x) const {
return x.dis < dis;
}
};
int dis[N];
bool vis[N];
void dij(int st){
priority_queue<Node> q;
q.push({0,st});
memset(vis,false,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[st]=0;
while(q.size()){
Node now = q.top();
q.pop();
if(vis[now.pos])continue;
vis[now.pos]=true;
for(int i=last[now.pos];i>0;i=a[i].next){
int v=a[i].u;
if(dis[now.pos]+a[i].val<dis[v]){
dis[v]=dis[now.pos]+a[i].val;
if(!vis[v]){
q.push({dis[v],v});
}
}
}
}
}
void solve(){
int st;
cin>>n>>m>>st;
memset(last,-1,sizeof(last));
tot=0;
rep(i,1,m){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
dij(st);
rep(i,1,n){
printf("%d ",dis[i]);
}
}
int main(){
solve();
return 0;
}