1. 程式人生 > >迪傑斯特拉(Dijkstra)演算法求圖中最短路徑

迪傑斯特拉(Dijkstra)演算法求圖中最短路徑

迪傑斯特拉(Dijkstra )演算法


對於圖G=(V,E),將圖的頂點分為兩組:
頂點集S:已求出的最短路徑的頂點集合(初始為{v0});
頂點集V-S:尚未求出最短路徑的頂點集合(初始為V-{v0} )。
演算法按最短路徑長度的遞增順序逐個將V-S的頂點加入S中,直到所有頂點均被加入S為止。

演算法需藉助輔助陣列dist[N], dist[i]表示目前已經找到的、從開始點v0到終點vi的當前最短路徑的長度。
dist各元素的初值:若從v0到vi存在弧,則dist[i]為弧上的權值;否則dist[i]為∞。

演算法執行過程

(1)當前下一條長度最短的路徑必為 ( v0, … , vk ),vk滿足如下條件:
dist[k]=Min{dist[i] | vi∈V-S}
求得頂點vk的最短路徑後,將vk加入頂點集S中。
修正:每加入一個新的頂點vk到頂點集S,則對V-S中剩餘的各頂點,多了一個“中轉”結點vk,從而可能多一條“中轉”路徑,新的中轉路徑可能小於原來的路徑,所以需對V-S剩餘的各頂點的最短路徑長度dist[i]進行修正。

(2)如何修正?
原來v0到vi的最短路徑長度為dist[i],加入vk後,以vk為中間頂點的“中轉”路徑長度為:dist[k] + wki,(wki為弧”<”vk, vi>上的權值),若“中轉”路徑長度小於原dist[i](即 dist[k] + wki < dist[i]),則將頂點vi的最短路徑長度修正為“中轉”路徑的長度。
(3)重複上述步驟(1)(2),直到所有頂點均加入S為止。

另外,為了記錄從v0出發到各頂點的最短“路徑”(頂點序列),使用輔助陣列path[ ], path[i]表示當前找到的從開始頂點v0到頂點vi的當前最短路徑頂點序列。
path[N]各元素的初值:如果從v0到vi有弧存在,則path[i]為(v0, vi);否則path[i]為空。

//Dijkstra演算法
#define INFINITY 32768
typedef unsigned int WeightType
typedef WeightType Adjtex
typedef Seqlist VertexSet;

ShortestPath_DJS(AdjMartrix g, int v0, WeightType dist[MAX_VERTEX_NUM],
VertexSet path[MAX_VERTEX_NUM]) {
/*path[i]中存放當前頂點i的最短路徑,是一個線性表。dist[i]中存放頂點i的當前最短路徑長度*/
    VertexSet s;     /*s為已找到最短路徑的終點集合*/
for(i = 0; i < g.vexnum; i++) { InitList(&path[i]); /*初始化dist[i]和path[i]*/ dist[i] = g.arcs.[v0][i].adj; /*dist[i]初始放當前頂點i到v0的路徑長度*/ if(dist[i] < INFINITY) { /*如果經過上一步權值存在(路徑存在)*/ AddTail(&path[i], g.vertex[v0]); /*AddTail是表尾新增操作*/ AddTail(&path[i], g.vertex[i]); /*構造從v0到i的路徑序列,儲存在順序表陣列的第i行*/ } } InitList(&s); AddTail(&s, g.vertex[v0]); /*將v0看成第一個已找到最短路徑的終點*/ for(t = 1; t <= g.vexnum - 1; t++) { /*求v0到其餘n-1個頂點額最短路徑(n=g.vexnum)*/ min = INFINITY; for(i = 0; t <= g.vexnum; i++) { if(!Member(g.vertex[i], s) && dist[i] < min) {//該點不存在s集合中且該點到v0的路徑存在 k = i; min = dist[i]; } } if(min == INFINITY) return; //如果經過上步沒有修改min的值,說明當前頂點到v0沒有路徑 回退 AddTail(&s, g.vertex[k]); //把當前頂點加到s集合中 for(i = 0; i < g.vertex; i++) { //如果該頂點不在s集合中且路徑存在且該點通過已經加進s集合的點建立的新路徑長度小於原路徑 if(!Member(g.vertex[i], s) && g.arcs[k][i].adj != INFINITY && (dist[k] + g.arc[k][i].adj < dist[i]) { dist[i] = dist[k] + g.arcs[k][i].adj; //修改dist[i]為即最新的最短路徑長度 path[i] = path[k]; //更新路徑 AddTail(&path[i], g.vertex[i]); /*path[i] = path[k]∪{vi}*/ } } } }


知乎:Solo | 微博@從流域到海域