天天看點

貪心算法——單源最短路徑 dijkstra

關于單源最短路徑的問題非常典型,這裡沒有給出分析與證明,僅僅給出了實作。

需要指出的是,許多實作僅給出了最短路徑的長度,而沒有給出“最短路徑”,這裡用給出了實作。

如程式中那樣,定義一個數組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 }

繼續閱讀