Dijkstra演算法
1.定義概覽
Dijkstra(迪傑斯特拉)演算法是典型的單源最短路徑演算法,用於計算一個節點到其他所有節點的最短路徑。主要特點是以起始點為中心向外層層擴充套件,直到擴充套件到終點為止。Dijkstra演算法是很有代表性的最短路徑演算法,在很多專業課程中都作為基本內容有詳細的介紹,如資料結構,圖論,運籌學等等。注意該演算法要求圖中不存在負權邊。
問題描述:在無向圖 G=(V,E) 中,假設每條邊 E[i] 的長度為 w[i],找到由頂點 V0 到其餘各點的最短路徑。(單源最短路徑)
2.演算法描述
1)演算法思想:設G=(V,E)是一個帶權有向圖,把圖中頂點集合V分成兩組,第一組為已求出最短路徑的頂點集合(用S表示,初始時S中只有一個源點,以後每求得一條最短路徑 , 就將加入到集合S中,直到全部頂點都加入到S中,演算法就結束了),第二組為其餘未確定最短路徑的頂點集合(用U表示),按最短路徑長度的遞增次序依次把第二組的頂點加入S中。在加入的過程中,總保持從源點v到S中各頂點的最短路徑長度不大於從源點v到U中任何頂點的最短路徑長度。此外,每個頂點對應一個距離,S中的頂點的距離就是從v到此頂點的最短路徑長度,U中的頂點的距離,是從v到此頂點只包括S中的頂點為中間頂點的當前最短路徑長度。
2)演算法步驟:
a.初始時,S只包含源點,即S={v},v的距離為0。U包含除v外的其他頂點,即:U={其餘頂點},若v與U中頂點u有邊,則<u,v>正常有權值,若u不是v的出邊鄰接點,則<u,v>權值為∞。
b.從U中選取一個距離v最小的頂點k,把k,加入S中(該選定的距離就是v到k的最短路徑長度)。
c.以k為新考慮的中間點,修改U中各頂點的距離;若從源點v到頂點u的距離(經過頂點k)比原來距離(不經過頂點k)短,則修改頂點u的距離值,修改後的距離值的頂點k的距離加上邊上的權。
d.重複步驟b和c直到所有頂點都包含在S中。
執行動畫如下圖(圖片來自網路):
演算法實現如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Dijkstra演算法 { class Program { static int length = 6; static string[] shortedPath = new string[length]; static int noPath = 2000; static int MaxSize = 1000; static int[,] G = { { noPath, noPath, 10, noPath, 30, 100 }, { noPath, noPath, 5, noPath, noPath, noPath }, { noPath, noPath, noPath, 50, noPath, noPath }, { noPath, noPath, noPath, noPath, noPath, 10 }, { noPath, noPath, noPath, 20, noPath, 60 }, { noPath, noPath, noPath, noPath, noPath, noPath } }; static string[] PathResult = new string[length]; static int[] path1 = new int[length]; static int[,] path2 = new int[length, length]; static int[] distance2 = new int[length]; static void Main(string[] args) { int dist1 = getShortedPath(G, 0, 5, path1); Console.WriteLine("Node 0 To 5:"); for (int i = 0; i < path1.Length; i++) Console.Write(path1[i].ToString() + " "); Console.WriteLine("Length:" + dist1); int[] pathdist = getShortedPath(G, 0, path2); Console.WriteLine("\nNode 0 To other:"); for (int j = 0; j < pathdist.Length; j++) { Console.WriteLine("Node 0 to " + j + " path:"); for (int i = 0; i < length; i++) { Console.Write(path2[j, i].ToString() + " "); } Console.WriteLine("length:" + pathdist[j]); } Console.ReadKey(); } //從某一源點出發,找到到某一結點的最短路徑 static int getShortedPath(int[,] G, int start, int end, int[] path) { bool[] s = new bool[length]; //表示找到起始結點與當前結點間的最短路徑 int min; //最小距離臨時變數 int curNode = 0; //臨時結點,記錄當前正計算結點 int[] dist = new int[length]; int[] prev = new int[length]; //初始結點資訊 for (int v = 0; v < length; v++) { s[v] = false; dist[v] = G[start, v]; if (dist[v] > MaxSize) prev[v] = 0; else prev[v] = start; } path[0] = end; dist[start] = 0; s[start] = true; //主迴圈 for (int i = 1; i < length; i++) { min = MaxSize; for (int w = 0; w < length; w++) { if (!s[w] && dist[w] < min) { curNode = w; min = dist[w]; } } s[curNode] = true; for (int j = 0; j < length; j++) if (!s[j] && min + G[curNode, j] < dist[j]) { dist[j] = min + G[curNode, j]; prev[j] = curNode; } } //輸出路徑結點 int e = end, step = 0; while (e != start) { step++; path[step] = prev[e]; e = prev[e]; } for (int i = step; i > step / 2; i--) { int temp = path[step - i]; path[step - i] = path[i]; path[i] = temp; } return dist[end]; } //從某一源點出發,找到到所有結點的最短路徑 static int[] getShortedPath(int[,] G, int start, int[,] path) { int[] PathID = new int[length];//路徑(用編號表示) bool[] s = new bool[length]; //表示找到起始結點與當前結點間的最短路徑 int min; //最小距離臨時變數 int curNode = 0; //臨時結點,記錄當前正計算結點 int[] dist = new int[length]; int[] prev = new int[length]; //初始結點資訊 for (int v = 0; v < length; v++) { s[v] = false; dist[v] = G[start, v]; if (dist[v] > MaxSize) prev[v] = 0; else prev[v] = start; path[v, 0] = v; } dist[start] = 0; s[start] = true; //主迴圈 for (int i = 1; i < length; i++) { min = MaxSize; for (int w = 0; w < length; w++) { if (!s[w] && dist[w] < min) { curNode = w; min = dist[w]; } } s[curNode] = true; for (int j = 0; j < length; j++) { if (!s[j] && min + G[curNode, j] < dist[j]) { dist[j] = min + G[curNode, j]; prev[j] = curNode; } } } //輸出路徑結點 for (int k = 0; k < length; k++) { int e = k, step = 0; while (e != start) { step++; path[k, step] = prev[e]; e = prev[e]; } for (int i = step; i > step / 2; i--) { int temp = path[k, step - i]; path[k, step - i] = path[k, i]; path[k, i] = temp; } } return dist; } } }