算法竞赛用—dijkstra算法

经典单源最短路径算法之一,优点是速度比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;
}	

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值