brief introduction
Dijkstra algorithm is a typical shortest path algorithm, which is used to calculate the shortest path from one node to other nodes. The main feature of BFS is that it extends from the starting point to the end
Dijkstra cannot handle graphs with negative weights and loops
Algorithmic thought
-
Set the starting point as u, and introduce two sets S and U. the set S contains the points of the shortest path that have been found. The set u records the points of the shortest path that have not been found and the distance to the starting point
-
Initializes two sets. At the beginning of set S, there is only the starting point. At the beginning of set U, it is the distance from the starting point to other nodes (in detail, the distance from the starting point to itself is 0, and the distance from the point where the starting point is not directly connected is INF)
-
Find the point k with the shortest path from the U set, join the S set and delete the point from the U set
-
Traverse all nodes. If a node v makes the distance from u to k and then to v smaller than the current distance from u to v, update the corresponding distance in U
-
Cycle the above steps 3 and 4 until the end of traversal to get the shortest path from the starting point to other nodes
By simply analyzing the above ideas, we can get the following pseudo codes (Purple Book p359)
Clear tags for all points in the tag array Let d[s]=0, other d[i]=INF,s is the starting point Cyclic n times { Select the node k with the lowest d value from all unmarked nodes Mark node k For all edges (k,i) starting from K, update d[i]=min{d[i],d[k]+w(k,i)} }
Where "update d[i]=min{d[i],d[k]+w(k,i)}" is called relaxation operation of edge (k,i)
code implementation
adjacency matrix
Time complexity O(V2), space complexity O(V2)
#define INF 0x3f3f3f3f const int N=1e3+10; int G[N][N]; //adjacency matrix int d[N]; //Shortest path from storage start point to other nodes bool vis[N]; //Displays whether the shortest path of the current node is updated int n; //Node number void Dijkstra(int u){ memset(d,0x3f,sizeof(d)); memset(vis,0,sizeof(vis)); d[u]=0; for(int i=1;i<=n;i++){ int k,m=INF; for(int j=1;j<=n;j++) if(!vis[j]&&d[j]<=m){ m=d[j]; k=j; } vis[k]=1; for(int j=1;j<=n;j++) d[j]=min(d[j],d[k]+G[k][j]); } for(int i=1;i<=n;i++) printf("%d%c",d[i],i==n?'\n':' '); }
Adjacency list
In fact, we find that the idea of the above adjacency matrix is not consistent with the algorithm. But when we write the adjacency table, we find that the queue we use is equivalent to the set U
The first method is what I learned when I studied purple book. Instead of opening vector < edge > a set of vector < edge > two-dimensional dynamic arrays, I directly used one-dimensional vector < edge > edges to save all the edges, and then used two-dimensional dynamic array vector < int > G [n] to save the subscript in the edge array corresponding to each starting point. In fact, it's similar to a chain forward star, but there's no chain forward star to save space
The vector array holds the number of the edge. With the number, you can find the specific information of the edge from the edges array. Thus, "for all edges (k,i) starting from K, update d[i]" becomes "for (int i = 0; I < G [u]. Size(); I + +) to perform relaxation operations on edge edges(G[u][i]).". On the whole, each edge is checked exactly once, so the number of slack executions is exactly m times. So just try to find the "node K with the lowest unmarked D value"
Obviously, we need priority queue maintenance d[i], that is, the smaller the d[i], the earlier we should be out of the queue. Therefore, priority queue of minimum heap maintenance needs priority queue < int, vector < int >, greater < int > > Q; however, we need not only the minimum value, but also the number corresponding to the minimum value, because we need to extract G[u][i] from the edge set according to the number U. Then we use the pair provided in STL directly, but we need to make [pair (d[i], I), because the smallest d[i] is taken in comparison, and the comparison of pair is to compare first and then second
For ease of use, the algorithm is encapsulated into a structure
typedef pair<int,int> P; const int maxn=1e5+10; //If you need to print out the path, 1e5 will burst the memory const int maxm=2e5+10; struct edge{ int from,to,w; edge(int a,int b,int c):from(a),to(b),w(c){} } struct Dijkstra{ int n,m; //Number of nodes and sides vector<edge> edges; vector<int> G[maxn]; //The number of all to sides under each from is recorded bool vis[maxn]; //Determine whether to mark int d[maxn]; //Distance from starting point to each node //int p[maxn]; / / the shortest previous edge void init(int n){ //Initialize structure this->n=n; for(int i=0;i<=n;i++) G[i].clear(); } void addEdge(int from,int to,int w){ edges.push_back(edge(from,to,w)); m=edges.size(); //Continuously update the number of sides G[from].push_back(m-1); //Because the number of each edge is unique in the edges array, just save the number (the number starts from 0, so M-1 is needed) } void dijkstra(int s){ priority_queue<P,vector<P>,greater<P> > q; memset(vis,0,sizeof(vis)); memset(d,0x3f,sizeof(d)); d[s]=0; q.push(make_pair(0,s)); //First construct a pair from s to itself, and it is obvious that d[s]=0 while(!q.empty()){ P pr=q.top(); q.pop(); int u=x.second; if(vis[u]) continue; vis[u]=1; for(int i=0;i<G[u].size();i++){ edge &e=edges[G[u][i]]; if(d[e.to]>d[u]+e.w){ d[e.to]=d[u]+e.w; //p[e.to]=G[u][i]; / / record the shortest path q.push(make_pair(d[e.to],e.to)); //There are multiple sides with the same starting point and ending point, all of which need to join the team } } } } void Print(){ //Print d[i] for(int i=1;i<=n;i++) printf("%d ",d[i]); } };
Chain forward star
Understand Chain forward star We can easily find that the idea of implementation is exactly the same as the adjacency list. However, the chain forward star is better than the above-mentioned adjacency list in both time and space, so we will try our best to use the chain forward star when we write the adjacency list in the future
There is a little change in the following code, which is also mentioned in purple book. Instead of Using vis tag array, we can use "if(pr.first!=d[u]) continue"; ", because we are here to see whether the minimum value of D taken out of the queue is equal to d[u]. If it is equal, then we don't need to judge. Because after entering the queue, we must take out the shortest circuit, and our d[u] was updated to the shortest circuit value last time
typedef pair<int,int> P; const int maxn=1e5+10; const int maxm=2e5+10; struct node{ int to,next,w; }; struct Dijkstra{ int n; int tot; int head[maxn]; node edge[maxm]; int d[maxn]; void init(int n){ this->n=n; tot=0; } void addEdge(int u,int v,int w){ tot++; edge[tot].w=w; edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot; } void dijkstra(int s){ priority_queue<P,vector<P>,greater<P> > q; memset(d,0x3f,sizeof(d)); d[s]=0; q.push(make_pair(0,s)); while(!q.empty()){ P pr=q.top(); q.pop(); int u=pr.second; if(pr.first!=d[u]) continue; for(int i=head[u];i;i=edge[i].next){ int v=edge[i].to; int w=edge[i].w; if(d[v]>d[u]+w){ d[v]=d[u]+w; q.push(make_pair(d[v],v)); } } } } void Print(){ for(int i=1;i<=n;i++) printf("%d ",d[i]); } };