单调队列+前向星的dijkstra算法,超详解~~

图论——最短路——dijkstra算法菜鸡详解

思路

利用前向星存图,用优先队列找到与前一个点相邻的未访问过的最短路。从起点开始,一次次找与起点s相连的最短的路e,dis[e]=min(dis[e],dis[s]+w[e][s]),如果这个点被更新而且之前没有加到队列过,那么就把他加到队列里面。直到队列为空为止。

例题

洛谷P4779
题目描述:
给定一个 nn 个点,mm 条有向边的带非负权图,请你计算从 ss 出发,到每个点的距离。数据保证你能从 ss 出发到任意点。

输入格式:
第一行为三个正整数 n, m, s。 第二行起 mm 行,每行三个非负整数 ui,vi,wi,表示从ui到vi有一条权值为wi的有向边。

输出格式
输出一行 nn 个空格分隔的非负整数,表示 ss 到每个点的距离。

dijkstra代码

#include<bits/stdc++.h>
using namespace std;
const int M = 2e5+5;
const int N = 1e5+5;

int n,m,s;
int vis[N],ru[N]={
    
    0};


struct ling{
    
      //前向星的结构体
	int e,w,next; 
	//e表示这条路终点,w表示路的长度,next表示上一个连接这条路的起点的终点
}dege[M];
int cnt=1,head[M];

void add(int u,int v,int w){
    
      //前向星
	dege[cnt].e=v;
	dege[cnt].w=w;
	dege[cnt].next=head[u];
	head[u]=cnt++;
}

struct node{
    
     
	int u,d;
	//u表示这条路的起点,d表示这个起点到初始点的距离
	node(int u,int d):u(u),d(d){
    
    }
	bool operator < (const node &a)const{
    
    
		return d>a.d; //最小堆
	}
};
priority_queue<node> q;

void dijk(int s){
    
    
	memset(ru,0,sizeof(ru));
	memset(vis,0x3f,sizeof(vis));
	vis[s]=0;
	q.push(node(s,vis[s]));
	while(!q.empty()){
    
    
		node t = q.top();q.pop();
		int u = t.u;
		int d = t.d;
	
		if(ru[u]) continue ; 
		//我第一次写成return,一直过不了……
		//应该是找不到就找下一条路
		ru[u]=1;
		for(int i=head[u];i>0;i=dege[i].next){
    
    
			int v = dege[i].e;
			int w = dege[i].w;
			
			if(vis[v]>d+w){
    
    
				vis[v]=d+w;
				q.push(node(v,vis[v]));
			}
		}
	}
}

int main(){
    
    
	ios::sync_with_stdio(false);
	memset(head,-1,sizeof(head));
	cin>>n>>m>>s;
	while(m--){
    
    
		int u,v,w;
		cin>>u>>v>>w;
		add(u,v,w);
	}
	dijk(s);
	for(int i=1;i<=n;++i){
    
    
		cout<<vis[i]<<" ";
	}
} 

总结

·dijkstra时间复杂度为(mlogm),算得上是比较快的了。
·但是他不能判断负权图,用的时候要注意哦!

猜你喜欢

转载自blog.csdn.net/qq_45758578/article/details/108649733