基本思路:首先从起点到所有可达的边进行查找,看是否能更新dist数组(dist[i]代表从源点到第i点的当前最短距离),同时在所有dist[i]中选择一个还没找到最短距离的点但是当前dist[i]是最短的点作为下次的起点,同时代表该点的最短距离被找到。一直循环,直到到达终点。每轮都能找到一个点的最短距离。
模板: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include <bits/stdc++.h> using namespace std;const int inf=0x7fffffff ;const int N=1e3 +8 ;int dist[N],map1[N][N],pre[N];int start,targe,n;int main () { scanf ("%d%d" ,&start,&targe); dist[start]=0 ,visit[start]=0 ; while (start!=targe){ int min=inf; int next=0 ; for (int i=1 ;i<=n;i++){ if (map[start][i]!=inf){ if (dist[i]>map[start][i]+dist[start]){ dist[i]=map[start][i]+dist[start]; pre[i]=start; } } if (visit[i]&&dist[i]<min){ next=i; min=dist[i]; } } if (min==inf)break ; start=next,visit[start]=0 ; } } void opt (int *pre,int end) { if (pre[end]!=end)opt (pre,pre[end]); printf ("%d " ,end); }
由上面的模板可以看出,我们朴素的dijkstra算法的时间复杂度大致为O(N^2),我们会发现,我们主要在邻接矩阵从起点,寻找可达的下一个点浪费了时间,以及寻找dist数组中的最小值时浪费了时间,那我们有什么办法可以将这个O(N)的遍历过程优化为O(logN)呢?
首先我们先解决邻接矩阵空间利用率低下而且遍历效率低下的问题,由于这里只需要我们找到可到的点,我们不妨用单链表将第一个点可以到的所有点串在一起,这样就减少了从一个点出发漫无目的的搜索,这里的单链表可以用动态数组vector定义一个数组map1
1 2 3 4 5 6 7 8 const int N=1e5 +6 ;struct roadmode { int to,dis; }; vector<roadmode> map1[N]; for (int i=0 ;i<map1[start].size ();i++){ }
或者我们还可以用链式前向星(下源码实现便是用的链式前向星)
接着我们还需要解决dist数组每轮寻找最小值需要消耗O(N)的问题,这个问题也很好解决,我们不妨维护一个小顶堆,配合一个vis数组即可解决。下面看具体实现代码。
dijkstra的堆优化: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 #include <bits/stdc++.h> using namespace std;const int maxn1=100004 ;const int maxn2=200004 ;int head[maxn1],dist[maxn1],visit[maxn1];int cnt,s,n,m;typedef struct Edge { int to,dis,next; }ID_Edge; ID_Edge edge[maxn2]; void Add_edge (int from,int to,int dis) { edge[++cnt].to=to; edge[cnt].dis=dis; edge[cnt].next=head[from]; head[from]=cnt; } struct Node { int id,dis; bool operator < (const Node &a) const { return a.dis<dis; } }; void dijkstra () { priority_queue<Node>q; q.push ((Node){s,0 }); for (int i=1 ;i<=n;i++){ dist[i]=-1 ; } dist[s]=0 ; while (!q.empty ()){ Node a=q.top (); q.pop (); if (visit[a.id]){ continue ; } visit[a.id]=1 ; for (int i=head[a.id];i!=0 ;i=edge[i].next){ if (dist[edge[i].to]==-1 ||(dist[a.id]+edge[i].dis<dist[edge[i].to])){ dist[edge[i].to]=dist[a.id]+edge[i].dis; q.push ((Node){edge[i].to,dist[edge[i].to]}); } } } } int main () { scanf ("%d%d%d" ,&n,&m,&s); for (int i=1 ;i<=m;i++){ int u,v,w; scanf ("%d%d%d" ,&u,&v,&w); Add_edge (u,v,w); } dijkstra (); for (int i=1 ;i<=n;i++){ printf ("%d " ,dist[i]); } return 0 ; }
我们不难发现,堆优化后,时间复杂度大概为O(Nlog(N))(我不知道为什么呜呜)。