關于單源最短路徑的問題非常典型,這裡沒有給出分析與證明,僅僅給出了實作。
需要指出的是,許多實作僅給出了最短路徑的長度,而沒有給出“最短路徑”,這裡用給出了實作。
如程式中那樣,定義一個數組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 }