Dijkstra算法详解

Posted szmssf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dijkstra算法详解相关的知识,希望对你有一定的参考价值。

前言

前几天研究的Bellman_Ford算法虽然可以算负权,可是时间复杂度高达O(NM),即使是采用了队列优化,也有可能被网格图卡回O(NM),所以今天我们就来研究一个新的,更快的,但同时只能在正权图上运行的算法:Dijkstra(朴素Dijkstra算法)

Dijkstra基本思想及实现过程

我们首先需要以下几个数组:dist[],vis[],用邻接矩阵需要g[][],邻接表则需要v[],w[],head[],nxt[]

邻接表与邻接矩阵在此不做过多解释,不懂的同学请自行百度,dist[i]表示i离源点的最短路距离,vis[i]==1就表示i号节点已经永久标号(之后会详细解释什么是永久标号)

算法步骤:

1)将源点距离初始化为0,其它点为正无穷INF

2)经过n次如下操作,得到源点离其它点的最短距离:

1、选择一个未扩展的点k,满足dist[k]是未扩展节点中离源点距离最小的;

2、对k进行永久标号

3、以k为中间点修改源点到其它点的最短路距离

时间复杂度O(N2),由于所有边权都为正,从而保证了算法的正确性。

朴素Dijkstra(邻接矩阵)

通过上边的步骤依次实现即可,下面给出参考程序:

#include<iostream>
#include<cstring>
#define inf 336860180
using namespace std;
int n,m,x,y,w,map[1000][1000],minn,dist[1000],t;
bool pd[1000];
int main()

	memset(map,20,sizeof(map));
	memset(dist,20,sizeof(dist));
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	
		map[i][i]=0;
	
	for(int i=1;i<=m;i++)
	
		cin>>x>>y>>w;
		map[x][y]=w;
	
	dist[1]=0;
	pd[1]=1;
	for(int i=1;i<=n;i++)
	
		t=1;minn=9999999;
		for(int j=1;j<=n;j++)
		
			if(pd[j]==0&&dist[j]<=minn)
			
				minn=dist[j];
				t=j;
			
		
		pd[t]=1;
		for(int j=1;j<=n;j++)
		
			dist[j]=min(dist[j],dist[t]+map[t][j]);
		
	
	for(int i=1;i<=n;i++)
	
		if(i-1)cout<<" ";
		if(dist[i]!=inf)cout<<dist[i];
		else cout<<"INF";
	
	return 0;

Dijkstra堆优化(邻接表+优先队列)

由于每次查找最短的点浪费大量时间,我们可以用优先队列进行查找,用pair记录,第一维记录最短距离,第二维记录点的编号,创建一个小根堆,每次取堆顶扩展即可。时间复杂度降为O((n+m)logm),参考程序如下:

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
typedef pair<long long,long long>P;
long long n,m,s,dist[100001],v[200005],w[200005],nxt[200005],head[200005],cnt,x,y,z;
bool vis[100001];
void add(long long a,long long b,long long c)

    v[++cnt]=b;
    w[cnt]=c;
    nxt[cnt]=head[a];
    head[a]=cnt;

void dijkstra(int s)

    memset(dist,20,sizeof(dist));
    priority_queue<P,vector<P>,greater<P> >q;
    dist[s]=0;
    q.push(P(0,s));
    while(!q.empty())
    
        long long c=q.top().second;
        q.pop();
        if(vis[c])continue;
        vis[c]=1;
        for(int i=head[c];i;i=nxt[i])
        
            int y=v[i];
            if(dist[y]>=dist[c]+w[i])
            
                dist[y]=dist[c]+w[i];
                q.push(P(dist[y],y));
            
        
    

int main()

    scanf("%d%d%d",&n,&m,&s);
    for(int i=1;i<=m;i++)
    
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
    
    dijkstra(s);
    for(int i=1;i<=n;i++)
    
        cout<<dist[i]<<" ";
    
    return 0;

  

 

以上是关于Dijkstra算法详解的主要内容,如果未能解决你的问题,请参考以下文章

Dijkstra算法A*算法D*算法LPA*算法和D* Lite算法详解汇总(原理matlab代码)格栅地图

Dijkstra算法A*算法D*算法LPA*算法和D* Lite算法详解汇总(原理matlab代码)格栅地图

最短路-Dijkstra算法:朴素版&堆优化版(Java详解)

Dijkstra最短路算法详解

Dijkstra 最短路径算法 秒懂详解

计算图的最短距离--Dijkstra算法