1. 程式人生 > >數據結構【圖】—025最短路徑距離

數據結構【圖】—025最短路徑距離

最短 賦權 oid 數組 動作 info 最終 所有 之前

/*********************************迪傑斯卡特(Dijstra)**************************/

講解:

1Dijkstra算法介紹

算法特點:

迪科斯徹算法使用了廣度優先搜索解決賦權有向圖或者無向圖的單源最短路徑問題,算法最終得到一個最短路徑樹。該算法常用於路由算法或者作為其他圖算法的一個子模塊。

算法的思路

Dijkstra算法采用的是一種貪心的策略,聲明一個數組dis來保存源點到各個頂點的最短距離和一個保存已經找到了最短路徑的頂點的集合:T,初始時,原點 s 的路徑權重被賦為 0 (dis[s] = 0)。若對於頂點 s 存在能直接到達的邊(s,m),則把dis[m]設為w(s, m),同時把所有其他(s不能直接到達的)頂點的路徑長度設為無窮大(1e4)。初始時,集合T只有頂點s

然後,從dis數組選擇最小值,則該值就是源點s到該值對應的頂點的最短路徑,並且把該點加入到T中,OK,此時完成一個頂點,

然後,我們需要看看新加入的頂點是否可以到達其他頂點並且看看通過該頂點到達其他點的路徑長度是否比源點直接到達短,如果是,那麽就替換這些頂點在dis中的值。

然後,又從dis中找出最小值,重復上述動作,直到T中包含了圖的所

2、Dijkstra算法示例演示

下面我求下圖,從頂點v1到其他各個頂點的最短路徑

技術分享圖片

首先第一步,我們先聲明一個dis數組,該數組初始化的值為:

技術分享圖片

我們的頂點集T的初始化為:T={v1}

既然是求 v1頂點到其余各個頂點的最短路程,那就先找一個離

1 號頂點最近的頂點。通過數組 dis 可知當前離v1頂點最近是 v3頂點。當選擇了 2 號頂點後,dis[2](下標從0開始)的值就已經從“估計值”變為了“確定值”,即 v1頂點到 v3頂點的最短路程就是當前 dis[2]值。將V3加入到T中。

為什麽呢?因為目前離 v1頂點最近的是 v3頂點,並且這個圖所有的邊都是正數,那麽肯定不可能通過第三個頂點中轉,使得 v1頂點到 v3頂點的路程進一步縮短了。因為 v1頂點到其它頂點的路程肯定沒有 v1 v3頂點短.

OK,既然確定了一個頂點的最短路徑,下面我們就要根據這個新入的頂點V3會有出度,發現以v3 為弧尾的有:

< v3,v4 >,那麽我們看看路徑:v1–v3–v4的長度是否比v1–v4短,其實這個已經是很明顯的了,因為dis[3]代表的就是v1–v4的長度為無窮大,而v1–v3–v4的長度為:10+50=60,所以更新dis[3]的值,得到如下結果:

技術分享圖片

因此 dis[3]要更新為 60。這個過程有個專業術語叫做“松弛”。即 v1頂點到 v4頂點的路程即 dis[3],通過 < v3,v4> 這條邊松弛成功。這便是 Dijkstra 算法的主要思想:通過“邊”來松弛v1頂點到其余各個頂點的路程。

然後,我們又從除dis[2]和dis[0]外的其他值中尋找最小值,發現dis[4]的值最小,通過之前是解釋的原理,可以知道v1到v5的最短距離就是dis[4]的值,然後,我們把v5加入到集合T中,然後,考慮v5的出度是否會影響我們的數組dis的值,v5有兩條出度:< v5,v4> < v5,v6>,然後我們發現:v1–v5–v4的長度為:50,而dis[3]的值為60,所以我們要更新dis[3]的值.另外,v1-v5-v6的長度為:90,而dis[5]為100,所以我們需要更新dis[5]的值。更新後的dis數組如下圖:

技術分享圖片

然後,繼續從dis中選擇未確定的頂點的值中選擇一個最小的值,發現dis[3]的值是最小的,所以把v4加入到集合T中,此時集合T={v1,v3,v5,v4},然後,考慮v4的出度是否會影響我們的數組dis的值,v4有一條出度:< v4,v6>,然後我們發現:v1–v5–v4–v6的長度為:60,而dis[5]的值為90,所以我們要更新dis[5]的值,更新後的dis數組如下圖:

技術分享圖片

然後,我們使用同樣原理,分別確定了v6和v2的最短路徑,最後dis的數組的值如下:

技術分享圖片

因此,從圖中,我們可以發現v1-v2的值為:∞,代表沒有路徑從v1到達v2。所以我們得到的最後的結果為:

起點 終點 最短路徑 長度

v1 v2

v3 {v1,v3} 10

v4 {v1,v5,v4} 50

v5 {v1,v5} 30

v6 {v1,v5,v4,v6} 60

算法實例:

先給出一個無向圖

技術分享圖片

用Dijkstra算法找出以A為起點的單源最短路徑步驟如下:

技術分享圖片

具體實現的代碼如下:

  1 #define MAXEDGE 20
  2 #define MAXVEX 20
  3 #define INFINITY 65535
  4 
  5 struct MGraph{
  6     int vexs[MAXVEX];
  7     int arc[MAXVEX][MAXVEX];
  8     int numVertexes, numEdges;
  9 };
 10 
 11 //創建圖的信息
 12 MGraph * CreateMGraph(MGraph *G)
 13 {
 14     int i, j;
 15 
 16     /* printf("請輸入邊數和頂點數:"); */
 17     G->numEdges = 16;
 18     G->numVertexes = 9;
 19 
 20     for (i = 0; i < G->numVertexes; i++)/* 初始化圖 */
 21     {
 22         G->vexs[i] = i;
 23     }
 24 
 25     for (i = 0; i < G->numVertexes; i++)/* 初始化圖 */
 26     {
 27         for (j = 0; j < G->numVertexes; j++)
 28         {
 29             if (i == j)
 30                 G->arc[i][j] = 0;
 31             else
 32                 G->arc[i][j] = G->arc[j][i] = INFINITY;
 33         }
 34     }
 35 
 36     G->arc[0][1] = 1;
 37     G->arc[0][2] = 5;
 38     G->arc[1][2] = 3;
 39     G->arc[1][3] = 7;
 40     G->arc[1][4] = 5;
 41 
 42     G->arc[2][4] = 1;
 43     G->arc[2][5] = 7;
 44     G->arc[3][4] = 2;
 45     G->arc[3][6] = 3;
 46     G->arc[4][5] = 3;
 47 
 48     G->arc[4][6] = 6;
 49     G->arc[4][7] = 9;
 50     G->arc[5][7] = 5;
 51     G->arc[6][7] = 2;
 52     G->arc[6][8] = 7;
 53 
 54     G->arc[7][8] = 4;
 55 
 56 
 57     for (i = 0; i < G->numVertexes; i++)
 58     {
 59         for (j = i; j < G->numVertexes; j++)
 60         {
 61             G->arc[j][i] = G->arc[i][j];
 62         }
 63     }
 64     return G;
 65 
 66 }
 67 
 68 void  ShortestPath_Dijkstra(MGraph *G) {
 69     vector<int>Res(MAXVEX, 0);//假設每個點的前向點都是v0點
 70     vector<int>Dis;//用來更新距離
 71     vector<bool>flag(MAXVEX, true);//記錄已經遍歷過的點
 72     int num = 0;//記錄已經遍歷過幾個點了
 73 
 74     for (int i = 0; i < G->numVertexes; ++i) 
 75         Dis.push_back(G->arc[0][i]);//首先假設0到各個點的距離為最短路徑,在此基礎上進行更新
 76 
 77     int start = 0;//起始點
 78     flag[start] = false;//該點踢出下次的選擇範圍
 79     ++num;//記錄遍歷過的點
 80 
 81     while (num < G->numVertexes) {
 82         int min = INFINITY;//最小值
 83         for (int j = 1; j < G->numVertexes; ++j) {
 84             if (flag[j] && min > Dis[j]) {//從剩下的點中找到距離最小的值
 85                 min = Dis[j];
 86                 start = j;
 87             }
 88         }
 89 
 90         flag[start] = false;//該點踢出下次的選擇範圍
 91         ++num;//記錄遍歷過的點
 92 
 93         for (int i = 0; i < G->numVertexes; ++i) {
 94             if (flag[i] && G->arc[start][i] + Dis[start] < Dis[i]) {//經過start點再到達點i的距離是否比原來的短?
 95                 Dis[i] = G->arc[start][i] + Dis[start];//更短就更新為更短的距離
 96                 Res[i] = start;//更新前向點為start
 97             }
 98         }
 99     }
100     
101     stack<int>s;
102     int end = G->numVertexes - 1;//記錄
103 
104     while (end) {//使用壓棧進行回溯出起始點到終點的路徑
105         s.push(end);
106         end = Res[end];
107     }
108     s.push(end);
109 
110     while (!s.empty()) {//打印出路徑
111         cout << s.top() << "->";
112         s.pop();
113     }
114     cout << endl << "總距離為:" << Dis[G->numVertexes - 1] << endl;
115 }
116 
117 
118 int T027(void) {
119     int i, j, v0;
120     MGraph *G;
121     G = new MGraph;
122     G = CreateMGraph(G);
123 
124     ShortestPath_Dijkstra(G);
125     return 0;
126 }

/**********************************弗洛伊德(Floyd)算法********************************************/

技術分享圖片

代碼如下:

  

  1 #include "000庫函數.h"
  2 
  3 #define MAXEDGE 20
  4 #define MAXVEX 20
  5 #define INFINITY 65535
  6 
  7 struct MGraph {
  8     int vexs[MAXVEX];
  9     int arc[MAXVEX][MAXVEX];
 10     int numVertexes, numEdges;
 11 };
 12 
 13 //創建圖的信息
 14 MGraph * CreateMGraph(MGraph *G)
 15 {
 16     int i, j;
 17 
 18     /* printf("請輸入邊數和頂點數:"); */
 19     G->numEdges = 16;
 20     G->numVertexes = 9;
 21 
 22     for (i = 0; i < G->numVertexes; i++)/* 初始化圖 */
 23     {
 24         G->vexs[i] = i;
 25     }
 26 
 27     for (i = 0; i < G->numVertexes; i++)/* 初始化圖 */
 28     {
 29         for (j = 0; j < G->numVertexes; j++)
 30         {
 31             if (i == j)
 32                 G->arc[i][j] = 0;
 33             else
 34                 G->arc[i][j] = G->arc[j][i] = INFINITY;
 35         }
 36     }
 37 
 38     G->arc[0][1] = 1;
 39     G->arc[0][2] = 5;
 40     G->arc[1][2] = 3;
 41     G->arc[1][3] = 7;
 42     G->arc[1][4] = 5;
 43 
 44     G->arc[2][4] = 1;
 45     G->arc[2][5] = 7;
 46     G->arc[3][4] = 2;
 47     G->arc[3][6] = 3;
 48     G->arc[4][5] = 3;
 49 
 50     G->arc[4][6] = 6;
 51     G->arc[4][7] = 9;
 52     G->arc[5][7] = 5;
 53     G->arc[6][7] = 2;
 54     G->arc[6][8] = 7;
 55 
 56     G->arc[7][8] = 4;
 57 
 58 
 59     for (i = 0; i < G->numVertexes; i++)
 60     {
 61         for (j = i; j < G->numVertexes; j++)
 62         {
 63             G->arc[j][i] = G->arc[i][j];
 64         }
 65     }
 66     return G;
 67 
 68 }
 69 
 70 void ShortestPath_Floyd(MGraph *G) {
 71     int Dis[MAXVEX][MAXVEX];//距離陣,進行更新
 72     int Path[MAXVEX][MAXVEX];//路徑前向點的矩陣
 73 
 74     for (int i = 0; i < G->numVertexes; ++i) {
 75         for (int j = 0; j < G->numVertexes; ++j) {
 76             Dis[i][j] = G->arc[i][j];//將初始的臨接矩陣賦值過來當初始距離陣
 77             Path[i][j] = j;//初始化路徑的前向點
 78         }
 79     }
 80 
 81     for (int k = 0; k < G->numVertexes; ++k) {
 82         for (int i = 0; i < G->numVertexes; ++i) {
 83             for (int j = 0; j < G->numVertexes; ++j) {
 84                 if (Dis[i][k] + Dis[k][j] < Dis[i][j]) {//i經過k到j的距離會不會比直接到j的距離短?
 85                     Dis[i][j] = Dis[i][k] + Dis[k][j];//更新i到j的距離
 86                     Path[i][j] = Path[i][k];//i到j的路徑中,要先從i到k
 87                 }
 88             }
 89         }
 90     }
 91     
 92     for (int i = 0; i < G->numVertexes; ++i) {
 93         int start = 0;//起始點固定為0
 94         vector<int>s;
 95         s.push_back(start);
 96         cout << "起點 0 到 " << i << " 的最短路徑為: " << endl;
 97         while (s.size() < i) {
 98             start = Path[start][i];
 99             s.push_back(start);
100         }
101         for (auto a : s)
102             cout << a << "—>";
103         cout << "最短距離為:" << Dis[0][i] << endl;
104     }
105 }
106 
107 void T028() {
108 
109     MGraph *G;
110     G = new MGraph;
111     G = CreateMGraph(G);
112     ShortestPath_Floyd(G);
113 }

數據結構【圖】—025最短路徑距離