Dijkstra算法的具体实现方法为:
2.在T集合中选取当前长度最短的一条最短路径(v0,…,vk),从而将vk加入到顶点集合S中,并修改源点v0到T中各顶点的最短路径长度;重复这一步骤,直到所有的顶点都加入到集合S中,算法就结束了。
算法实现:
在Dijkstra算法里,为了求源点v0到其他各顶点vi的最短路径及其长度,需要设置3个数组:
a) dist[n]:dist[i]表示当前找到的从源点v0到终点vi的最短路径的长度,初始时,dist[i]为Edge[v0][i],即邻接矩阵的第v0行。
b) S[n]:S[i]为0表示顶点vi还未加入到集合S中,S[i]为1表示vi已经加入到集合S中。初始时,S[v0]为1,其余为0,表示最初集合S中只有顶点v0。
c) path[n]:path[i]表示v0到vi的最短路径上顶点vi的前一个顶点序号。采用“倒向追踪”的方法,可以确定v0到顶点vi的最短路径上的每个顶点。
在Dijkstra算法里,重复做以下3步工作:
1) 在数组dist[n]里查找S[i] != 1,并且dist[i]最小的顶点u;
2) 将S[u]改为1,表示顶点u已经加入进来了;
3) 修改T集合中每个顶点vk的dist及path数组元素值:当S[k] != 1,且顶点u到顶点vk有边(Edge[u][k]<MAX),且dist[u] + Edge[u][k] < dist[k],则修改dist[k]为dist[u] + Edge[u][k],修改path[k]为u。
因此Dijkstra算法的递推公式(求源点v0到各顶点的最短路径)为:
eg:
利用Dijkstra算法求下图中顶点0到其他各顶点的最短路径长度,并输出对应的最短路径。
假设数据输入时采用如下的格式进行输入:首先输入顶点个数n,然后输入每条边的数据。每条边的数据格式为:u v w,分别表示这条边的起点、终点和边上的权值。顶点序号从0开始计起。最后一行为-1 -1 -1,表示输入数据的结束。
#include <iostream> #include <cstring> #include <cstdio> using namespace std; const int MAXN = 20; const int INF = 1000010; int dist[MAXN]; int path[MAXN]; int S[MAXN]; int Edge[MAXN][MAXN]; int n; void Dijkstra(int v0) { int i, j; memset(dist, 0, sizeof(dist)); for (i = 0; i < n; ++i) { dist[i] = Edge[v0][i];//初始时dist中存放v0所在的行 S[i] = 0; if (i != v0 && dist[i] < INF) path[i] = v0; else path[i] = -1; } S[v0] = 1, dist[v0] = 0;//只有v0 在S中 for (i = 0; i < n-1; ++i) { int MIN = INF, v = v0; for (j = 0; j < n; ++j) { if ( !S[j] && MIN > dist[j] )//在T中找具有最短路径的定点v { MIN = dist[j]; v = j; } } S[v] = 1;//表示v已经加入进来 for (j = 0; j < n; ++j)//由于v的加入,可能会导致v0到T中顶点dist[]值“缩短”,如果dist的值修改自然也要修改path { if (!S[j] && Edge[v][j] < INF && (dist[v] + Edge[v][j] < dist[j])) { dist[j] = dist[v] + Edge[v][j]; path[j] = v; } } } } int main() { int i, j; int u, v, w; cin>>n; while (1) { cin>>u>>v>>w; if(u == -1 && v == -1 && w == -1) break; Edge[u][v] = w; } for (i = 0; i < n; ++i) { for (j = 0; j < n; ++j) { if(i == j) Edge[i][j] = 0; else if(Edge[i][j] == 0) Edge[i][j] = INF; } } Dijkstra( 0 ); int shortest[MAXN]; for (i = 1; i < n; ++i) { cout<<dist[i]<<"\t"; memset(shortest, 0, sizeof(shortest));//找到从v0到i的最短路径上的点 int k = 0; shortest[k] = i; while (path[ shortest[k] ] != 0) { k++; shortest[k] = path[ shortest[k-1] ]; } k++; shortest[k] = 0; for(j = k; j > 0; --j) cout<<shortest[j]<<" -> "; cout<<shortest[0]<<endl; } return 0; }