最短路模板——dijksttra(注意事项和易错点)

关于dijkstra


主要使用优先队列进行优化,时间复杂度为O(\(m log n\))。
对于稠密图来说,可以使用原版dijkstra,时间复杂度为O(\(n^2\))

以下是标准代码。


标准代码1:(加队列优化)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<iomanip>

#define N 100002
#define M 200002 

using namespace std;

long long n,m,st,head[N],go[M],nxt[M],w[M],d[N],tot=0;
bool v[N];

priority_queue<pair<long long,long long> > q;

long long read(){
	long long x=0,h=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')h=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+(long long)(ch-'0');ch=getchar();}
	return x*h;
}

void add(long long x,long long y,long long z){
	go[++tot]=y;nxt[tot]=head[x];head[x]=tot;w[tot]=z;
	return ;
}

void dijkstra(){
	memset(v,0,sizeof(v));
	memset(d,0x3f,sizeof(d));
	q.push(make_pair(0,st));d[st]=0;
	while(!q.empty()){
		long long x=q.top().second;q.pop();
		if(v[x])continue;
		v[x]=1; 
		for(long long i=head[x];i;i=nxt[i]){
			long long y=go[i];
			if(d[x]+w[i]>=d[y])continue;
			d[y]=d[x]+w[i];
			q.push(make_pair(-d[y],y));
		}
	}
	return ;
}

int main(){
	n=read();m=read();st=read();
	for(long long i=1;i<=m;i++){
		long long x=read(),y=read(),z=read();
		add(x,y,z);
	}
	dijkstra();
	for(long long i=1;i<=n;i++)printf("%lld ",d[i]);
	return 0;
}

对于此代码来说,需要注意以下几点

  1. if(v[x])continue; v[x]=1; 必须写在循环外侧。因为在一张图中,同一个点的值可能被更新多次,但是当优先队列将其取出时,一定是最小的,所以如果之前已经出过队,就没有必要再次从这个点出发更新其他点。(划重点!!!)
  2. 需要使用优先队列来做,pair<int,int>在优先队列中是按first值排序的。
  3. 从简洁性来考虑,取出队头时应写成 long long x=q.top().second; ,而不是 pair<long long,long long> x=q.top();
  4. 在最后用 long long 替换 int 时,要注意将 printf%d 改为 %lld
  5. priority_queue<int> q 是大根堆,堆头是最大值。 priority<int,vector<int>,greater<int> > q 是小根堆,但这种小根堆只能使用 intlong long ,不能使用 pair<int,int>

标准代码2:(原版)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<iomanip>

#define N 1002
#define MAX 4557430888798830399

using namespace std;
long long n,m,st,mp[N][N],d[N];
bool v[N];

long long min(long long a,long long b){
   return a<b ? a:b;
}

long long read(){
   long long x=0,h=1;char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')h=-1;ch=getchar();}
   while(ch>='0'&&ch<='9'){x=x*10+(long long)(ch-'0');ch=getchar();}
   return x*h;
}

void dijkstra(){
   memset(v,0,sizeof(v));
   memset(d,0x3f,sizeof(d));
   d[st]=0;
   for(long long i=1;i<n;i++){
   	long long x=0;
   	for(long long j=1;j<=n;j++){
   		if((!v[j])&&(x==0||d[j]<d[x]))x=j;
   	}
   	v[x]=1;
   	for(long long j=1;j<=n;j++){
   		d[j]=min(d[j],d[x]+mp[x][j]);
   	}
   }
   return ;
}

int main(){
   memset(mp,0x3f,sizeof(mp));
   n=read();m=read();st=read();
   for(int i=1;i<=n;i++)mp[i][i]=0;
   for(long long i=1;i<=m;i++){
   	long long x=read(),y=read(),z=read();
   	mp[x][y]=min(mp[x][y],z);
   }
   dijkstra();
   for(long long i=1;i<=n;i++){
   	if(d[i]==MAX)printf("2147483647 ");
   	else printf("%lld ",d[i]);
   }
   return 0;
}

对于此代码来说,需要注意以下几点:

  1. 注意邻接矩阵的初值。
  2. 在找最小值中,一定要加 x==0 的判断

以上两组标准代码分别以P3371 【模板】单源最短路径(弱化版)P4779 【模板】单源最短路径(标准版)为模板

posted @ 2021-07-10 00:37  Charisk_FOD  阅读(115)  评论(0)    收藏  举报