Dijkstra算法是解单源最短路径问题的一个贪心算法。
其基本思想是:设置顶点集合S并不断地做贪心选择来扩充这个集合。一个顶点属于S当且仅当从源到该顶点的最短路径长度已知。
初始时,S中仅含有源。设u是G的某一个顶点,把从源到u且中间只经过S中顶点的路径称为从源到u的特殊路径,并且用数组dist记录当前每个顶点所对应的最短特殊路径长度。Dijkstra算法每次从V-S中取出具有最短特殊路长度的顶点u,将u添加到S中,同时对数组dist做出必要的修改。一旦S包含了所有V中顶点,dist就记录了从源到所有其他顶点之间的最短路径长度。
Dijkstra算法可描述如下,其中输入的带权的有向图G=(V,E),V={1,2,…,n},顶点v是源。c是一个二维数组,c[ i ][ j ]表示边(i,j)不属于E时,c[ i ][ j ]是一个大数。disk[i]表示当前从源到顶点i的最短特殊路径长度
当然我们可以根据上述算法思想用二维数组写出最简单的Dijkstra算法
[cpp]
view plain
copy
- void Dijkstra(int n,int v, type dist[], int prev[],type **c)
- {
- //s[i]为true,则顶点 ; s[i]为true,则顶点
- bool s[n+1];
- // 初始化,其中顶点1为源
- for(int i=1;i<=n;i++)
- {
- dist[i]=c[v][i];
- s[i]=false;
- if(dist[i]==maxint) prev[i]=0; // 没有路直接到源
- else prev[i]=1 //有路直接到源
- }
- disk[v]=0;
- s[v]=true; // 起始时,只有源属于集合S
- //将其余n-1个顶点添加到集合S中,每次循环添加一个顶点到S中
- for(int i=1;i<n;i++)
- {
- // 从V-S中取出具有最短路径长度的顶点u,将u添加到S中
- int temp=maxint; int u=1;
- for(int j=1; j<=n; j++)
- if((!s[j])&&(dis[j]<temp))
- {
- u=j;
- temp=dist[j];
- }
- s[u]=true;
- //在S中添加顶点u后,对数组dist做必要的修改
- for(int j=2; j<=n; j++)
- if((!s[j])&&(c[u][j]<maxint))
- {
- type newdist=dist[u]+c[u][j];
- if(newdist<dist[j]
- {
- dist[j]=newdist;
- prev[j]=u;
- }
- }
- }
- }
在很多情况下,点会有很多,但是边却没有那么多,这样的话,二维数组中就会有很多没有被利用,这不仅浪费内存,而且速度也会受到一定的影响。在这种情况下,我们就可以采用邻接矩阵或者heap 或者是优先队列来优化Dijkstra算法:
下面给出它的优先队列优化Dijkstra算法
[cpp]
view plain
copy
- #include<vector>
- #include<queue>
- struct Edge
- {
- int from ;
- int to;
- int dist;
- };
- //Dijkstra算法用到优先队列的结点
- struct HeapNode
- {
- int d,u;
- bool operator < (const HeapNode& rhs) const
- {
- return d > rhs.d;
- }
- };
- struct Dijkstra
- {
- int n;
- long m;//点数和边数
- vector<Edge> edges;//边列表
- vector<int> G[MAX];//每个结点出发的边编号(从0 开始编号)
- bool done[MAX];//是否已永久标号
- int d[MAX]; //s到各个点的距离
- int p[MAX];//最短路中的上一条边
- void init(int n)
- {
- this->n = n;
- for(int i = 0 ; i < n ;i++)
- G[i].clear();//清空邻接表
- edges.clear();//清空边表
- }
- void AddEdge(int from,int to,int dist)
- {
- //如果是无向图,每条边需调用两次AddEdge
- Edge e;
- e.from = from ;
- e.to = to;
- e.dist = dist;
- edges.push_back(e);
- int mm = edges.size();
- G[from].push_back(mm-1);
- }
- void dijkstra(int s)
- {
- //求s到所有点的距离
- priority_queue<HeapNode> Q;
- for(int i=0;i<n;i++)
- d[i]=INT_MAX;
- d[s]=0;
- memset(done,0,sizeof(done));
- HeapNode h0;
- h0.d=0;
- h0.u=s;
- Q.push(h0);
- while(!Q.empty())
- {
- HeapNode x = Q.top();
- Q.pop();
- int u = x.u;
- if(done[u])
- continue;
- done[u] = true;
- for(int i=0;i<G[u].size();i++)
- {
- Edge& e = edges[G[u][i]];
- if(d[e.to] > d[u] + e.dist)
- {
- d[e.to] = d[u] + e.dist;
- p[e.to] = G[u][i];
- HeapNode h;
- h.d = d[e.to];
- h.u = e.to;
- Q.push(h);
- }
- }
- }
- }
- };