关于单源最短路径的问题非常典型,这里没有给出分析与证明,仅仅给出了实现。
需要指出的是,许多实现仅给出了最短路径的长度,而没有给出“最短路径”,这里用给出了实现。
如程序中那样,定义一个数组p[N],其中p[i]代表“起始点v到顶点i的最短路径中,除i本身的最后一个顶点”,即着这条路径上i的前驱顶点,这个顶点随着“更多顶点的最短路径被求出”这个过程而变化。
当求出v到所有顶点的最短路径以后,同时也求出了最终的p[N]。于是可以按下列回溯的方法来求出每条最短路径序列:
对于顶点j,在其最短路径上其前驱pre = p[j],i=<pre<n且pre!=j,说明“到顶点j的最短路径”是基于“到顶点pre的最短路径”的,这样一直回溯,直到pre=v(单源点),这些pre值就构成了最短路径序列。
1 #include <iostream> 2 using namespace std; 3 #define N 5 4 #define MAX 65535 5 int g[N][N]; 6 void min_path(int v,long *d,int *p) 7 { 8 int i = 0; 9 int j = 0; 10 bool s[N]={false}; 11 for(i=0;i<N;i++) 12 for(j=0;j<N;j++) 13 if(g[i][j] == -1) 14 g[i][j] = 65536; 15 for(i = 0;i<N;i++) 16 { 17 d[i] = g[v][i]; 18 if(d[i] == MAX) 19 p[i] = 0; 20 else 21 p[i] = v; 22 } 23 24 s[v] = true; 25 d[v] = 0; 26 p[v] = 0; 27 28 int k = 0; 29 for(i = 0 ;i<N;i++) 30 { 31 int min = 65535; 32 for(j = 0 ;j<N;j++) 33 { 34 if(j != v && s[j] == false) 35 { 36 if(d[j]<=min) 37 { 38 min = d[j]; 39 k = j;//k是V集合中具有最短“特殊路径的顶点”,所谓特殊路径即是从顶点v到k只经过U中的顶 点。 40 } 41 } 42 } 43 s[k] = true;//将k从V集合中并入到U集合中 44 for(j=0;j<N;j++) 45 { 46 if(s[j]==false && d[j]>d[k]+g[k][j]) 47 { 48 d[j] = d[k] + g[k][j];//更新其他在V中的顶点的最短距离。 49 p[j] = k; 50 } 51 } 52 } 53 } 54 int main() 55 { 56 long d[N]; 57 int p[N];//p[i]代表到达顶点i的最短路径的前驱节点,随着路径变化而变化 58 int i = 0; 59 for(i = 0;i<N;i++) 60 { 61 for(int j = 0;j<N;j++) 62 cin>>g[i][j]; 63 } 64 min_path(0,d,p); 65 for( i =0;i<N;i++) 66 cout << d[i] << ” “; 67 cout << endl; 68 //输出每条最短路径 69 for(i = 0;i<N;i++) 70 { 71 //if(i != 0) 72 { 73 int pre = p[i]; 74 while(pre!=0) 75 { 76 cout << pre << ” “; 77 pre = p[pre]; 78 } 79 cout << endl; 80 } 81 } 82 }