前言
前几天研究的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