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;
}

  

原文地址:https://www.cnblogs.com/szmssf/p/10980237.html

时间: 2024-10-15 18:46:02

Dijkstra算法详解的相关文章

图的最短路径-----------Dijkstra算法详解(TjuOj2870_The Kth City)

做OJ需要用到搜索最短路径的题,于是整理了一下关于图的搜索算法: 图的搜索大致有三种比较常用的算法: 迪杰斯特拉算法(Dijkstra算法) 弗洛伊德算法(Floyd算法) SPFA算法 Dijkstra算法使用了广度优先搜索解决赋权有向图或者无向图的单源最短路径问题,算法最终得到一个最短路径树. 算法的思路: Dijkstra算法采用的是一种贪心的策略,声明一个数组dis来保存源点到各个顶点的最短距离和一个保存已经找到了最短路径的顶点的集合:T,初始时,原点 s 的路径权重被赋为 0 (dis

最短路径问题---Dijkstra算法详解

原文地址:https://www.cnblogs.com/captain-dl/p/10254650.html

最短路径问题---Floyd算法详解

前言 Genius only means hard-working all one's life. Name:Willam Time:2017/3/8 1.最短路径问题介绍 问题解释: 从图中的某个顶点出发到达另外一个顶点的所经过的边的权重和最小的一条路径,称为最短路径 解决问题的算法: 迪杰斯特拉算法(Dijkstra算法) 弗洛伊德算法(Floyd算法) SPFA算法 之前已经对Dijkstra算法做了介绍(不懂的可以看这篇博客:Dijkstra算法详解),所以这篇博客打算对Floyd算法做

最短路算法 :Bellman-ford算法 &amp; Dijkstra算法 &amp; floyd算法 &amp; SPFA算法 详解

 本人QQ :2319411771   邮箱 : [email protected] 若您发现本文有什么错误,请联系我,我会及时改正的,谢谢您的合作! 本文为原创文章,转载请注明出处 本文链接   :http://www.cnblogs.com/Yan-C/p/3916281.html . 很早就想写一下最短路的总结了,但是一直懒,就没有写,这几天又在看最短路,岁没什么长进,但还是加深了点理解. 于是就想写一个大点的总结,要写一个全的. 在本文中因为邻接表在比赛中不如前向星好写,而且前向星效率并

最短路SPFA 算法详解

最短路SPFA 算法详解 适用范围:给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了. 我们约定有向加权图G不存在负权回路,即最短路径一定存在.当然,我们可以在执行该算法前做一次拓扑排序,以判断是否存在负权回路,但这不是我们讨论的重点. 算法思想:我们用数组d记录每个结点的最短路径估计值,用邻接表来存储图G.我们采取的方法是动态逼近法:设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并

EM算法(3):EM算法详解

目录 EM算法(1):K-means 算法 EM算法(2):GMM训练算法 EM算法(3):EM算法详解

[转] KMP算法详解

转载自:http://www.matrix67.com/blog/archives/115 KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段.    我们这里说的KMP不是拿来放电影的(虽然我很喜欢这个软件),而是一种算法.KMP算法是拿来处理字符串匹配的.换句话说,给你两个字符串,你需要回答,B串是否是A串的子串(A串是否包含B串).比如,字符串A="I'm matrix67",字符串B="matrix",我们就说B是A的子串.

[搜索]波特词干(Porter Streamming)提取算法详解(3)

 接上 [搜索]波特词干(Porter Streamming)提取算法详解(2) 下面分为5大步骤来使用前面提到的替换条件来进行词干提取. 左边是规则,右边是提取成功或者失败的例子(用小写字母表示). 步骤1 SSES -> SS                   caresses  ->  caress IES  -> I                          ponies    ->  poni ties      ->  ti SS   -> S

KMP算法详解(图示+代码)

算法过程非常绕,不要企图一次就能看明白,多尝试就会明白一些.下面试图用比较直观的方法解释这个算法,对KMP算法的解释如下: 1. 首先,字符串"BBC ABCDAB ABCDABCDABDE"的第一个字符与搜索词"ABCDABD"的第一个字符,进行比较.因为B与A不匹配,所以搜索词后移一位. 2. 因为B与A不匹配,搜索词再往后移. 3. 就这样,直到字符串有一个字符,与搜索词的第一个字符相同为止. 4. 接着比较字符串和搜索词的下一个字符,还是相同. 5. 直到字