當前位置:首頁 » 操作系統 » dijkstra演算法優化

dijkstra演算法優化

發布時間: 2023-04-19 19:34:37

① 在解決最短路徑優化問題中,Dijkstra演算法有哪些優.缺點

優點:演算法簡明、能得到最優解
缺點:效率低(特別是有時候不需要最優解)、運算中佔用空間大

② 圖文解析 | Dijkstra單源最短路徑演算法

給定 加權有向圖 G=(V,E,W),每條邊的權值w為 非負數 ,表示兩個頂點間的距離。

源點s∈V。

求:從s出發到其他各個頂點的最短路徑。

如上圖所示,以1為源點,計算到其餘各個頂點的最短距離(我已用紅線標出)。下面列出了最終解:

S集合 :當從s到x(x ∈V )的最短路徑找到時,則x ∈S。當所有頂點都進入S集合時,演算法結束。

初始:S={s},當S=V時演算法結束。

從s到u相對於S的最短路徑 :指從s到u且僅經過S中頂點的最短路徑。

dist[u]:從s到u相對於S的最短路徑長度

short[u]:從s到u最短路徑的長度(演算法最終解)

dist[u] ≥ short[u]

Dijkstra演算法採用貪心演算法模式,演算法過程就是通過計算dist[u],不斷擴充S集合,同時dist[u]會不斷優化改善,直到dist[u] = short[u],並將其放到S中,當所有頂點都放入S集合時,演算法結束。

輸入:加權有向圖G=(V,E,W)

          V={1,2,…,n}, s=1

輸出:從s到每個頂點的最短路徑

輸入:G=(V,E,W),源點1

          V={1,2,3,4,5,6}

初始S集合只有1,計算直接從1能到達的頂點的距離,其他不能從1號頂點直接到達的頂點都記為無窮大。雀輪睜此時從dist[u]里找出最短距離的頂點(6號),並將其放進S集合。

  S={1}

  dist[1] = 0

  dist[2] = 10

  dist[6 ] = 3

  dist[3] = ∞

  dist[4] = ∞

  dist[5] = ∞

當把6號頂點放進S集合後,經由6號頂點出發到達的頂點的最短距離可能會被優化更新,因為該演算法的思想很「貪心」,誰更短我要誰!比如1->6->2要比1->2距離更短,所以dist[2]被更頃歲新為5,從專業術語上講,這個「更新」過程叫做鬆弛,其他點同理。然桐喚後從dist[u]里找出最短的路徑的那個頂點(5號),並放進S集合里。

  S={1,6}

  dist[1] = 0

 dist[6] = 3

  dist[2] = 5

  dist[4] = 9

  dist[5] = 4

  dist[3] = ∞

後面的操作步驟其實就是重復上面的操作。即當S集合里有個新的頂點後,就可能會更新其他點的最短距離,更新一遍後,找出當前最短距離的dist[u],並將該頂點放進S集合。後面不重復闡述。

  S={1,6,5}

  dist[1] = 0

 dist[6] = 3

  dist[5] = 4

  dist[2] = 5

  dist[4] = 9

  dist[3] = ∞

  S={1,6,5,2}

  dist[1] = 0

 dist[6] = 3

  dist[5] = 4

 dist[2] = 5

  dist[4] = 9

  dist[3] = 12

  S={1,6,5,2,4}

  dist[1] = 0

 dist[6] = 3

  dist[5] = 4

 dist[2] = 5

 dist[4] = 9

  dist[3] = 12

  S={1,6,5,2,4,3}

  dist[1] = 0

 dist[6] = 3

  dist[5] = 4

 dist[2] = 5

 dist[4] = 9

 dist[3] = 12

當有向圖中的所有頂點都進入了S集合後,演算法結束,此時的dist[u]的值其實就是最初我們找出的那個最終解short[u],所以,演算法結束時,dist[u]=short[u],得到最終解。

③ dijkstra演算法是什麼

迪傑斯特拉演算法用來解決從頂點v0出發到其餘頂點的最短路徑,該演算法按照最短路徑長度遞增的順序產生所以最短路徑。

對於圖G=(V,E),將圖中的頂點分成兩組:第一組S:已求出的最短路徑的終點集合(開始為{v0})。第二組V-S:尚未求出最短路徑的終點集合(開始為V-{v0}的全部結點)。

堆優化

思考

該演算法復雜度為n^2,我們可以發現,如果邊數遠小於n^2,對此可以考慮用堆這種數據結構進行優化,取出最短路徑的復雜度降為O(1);每次調整的復雜度降為O(elogn);e為該點的邊數,所以復雜度降為O((m+n)logn)。

實現

1、將源點加入堆,並調整堆。

2、選出堆頂元素u(即代價最小的元素),從堆中刪除,並對堆進行調整。

3、處理與u相鄰的,未被訪問過的,滿足三角不等式的頂點

1):若該點在堆里,更新距離,並調整該元素在堆中的位置。

2):若該點不在堆里,加入堆,更新堆。

4、若取到的u為終點,結束演算法;否則重復步驟2、3。

④ 最短路徑 | 深入淺出Dijkstra演算法(一)

上次我們介紹了神奇的只有 五行的 Floyd-Warshall 最短路演算法 ,它可以方便的求得 任意兩點的最短路徑, 這稱為 「多源最短路」。

這次來介紹 指定一個點(源點)到其餘各個頂點的最短路徑, 也叫做 「單源最短路徑」。 例如求下圖中的 1 號頂點到 2、3、4、5、6 號頂點的最短路徑。

與 Floyd-Warshall 演算法一樣,這里仍然 使用二維數組 e 來存儲頂點之間邊的關系, 初始值如下。

我們還需要用 一個一維數組 dis 來存儲 1 號頂點到其餘各個頂點的初始路程, 我們可以稱 dis 數組為 「距離表」, 如下。

我們將此時 dis 數組中的值稱為 最短路的「估計值」。

既然是 求 1 號頂點到其餘各個頂點的最短路程, 那就 先找一個離 1 號頂點最近的頂點。

通過數組 dis 可知當前離 1 號頂點最近是 2 號頂點。 當選擇了 2 號頂點後,dis[2]的值就已經從「估計值」變為了「確定值」, 即 1 號頂點到 2 號頂點的最短路程就是當前 dis[2]值。

為什麼呢?你想啊, 目前離 1 號頂點最近的是 2 號頂點,並且這個圖所有的邊都是正數,那麼肯定不可能通過第三個頂點中轉,使得 1 號頂點到 2 號頂點的路程進一步縮短了。 因此 1 號頂點到其它頂點的路程肯定沒有 1 號到 2 號頂點短,對吧 O(∩_∩)O~

既然選了 2 號頂點,接下來再來看 2 號頂點 有哪些 出邊 呢。有 2->3 和 2->4 這兩條邊。

先討論 通過 2->3 這條邊能否讓 1 號頂點到 3 號頂點的路程變短。 也就是說現在來比較 dis[3] dis[2]+e[2][3] 的大小。其中 dis[3]表示 1 號頂點到 3 號頂點的路程,dis[2]+e[2][3]中 dis[2]表示 1 號頂點到 2 號頂點的路程,e[2][3]表示 2->3 這條邊。所以 dis[2]+e[2][3]就表示從 1 號頂點先到 2 號頂點,再通過 2->3 這條邊,到達 3 號頂點的路程。

我們發現 dis[3]=12,dis[2]+e[2][3]=1+9=10,dis[3]>dis[2]+e[2][3],因此 dis[3]要更新為 10。這個過程有個專業術語叫做 「鬆弛」 。即 1 號頂點到 3 號頂點的路程即 dis[3],通過 2->3 這條邊 鬆弛成功。 這便是 Dijkstra 演算法的主要思想: 通過 「邊」 來鬆弛 1 號頂點到其餘各個頂點的路程。

同理通過 2->4(e[2][4]),可以將 dis[4]的值從 ∞ 鬆弛為 4(dis[4]初始為 ∞,dis[2]+e[2][4]=1+3=4,dis[4]>dis[2]+e[2][4],因此 dis[4]要更新為 4)。

剛才我們對 2 號頂點所有的出邊進行了鬆弛。鬆弛完畢之後 dis 數組為:

接下來,繼續在剩下的 3、4、5 和 6 號頂點中,選出離 1 號頂點最近的頂點。通過上面更新過 dis 數組,當前離 1 號頂點最近是 4 號頂點。此時,dis[4]的值已經從「估計值」變為了「確定值」。下面繼續對 4 號頂點的所有出邊(4->3,4->5 和 4->6)用剛才的方法進行鬆弛。鬆弛完畢之後 dis 數組為:

繼續在剩下的 3、5 和 6 號頂點中,選出離 1 號頂點最近的頂點,這次選擇 3 號頂點。此時,dis[3]的值已經從「估計值」變為了「確定值」。對 3 號頂點的所有出邊(3->5)進行鬆弛。鬆弛完畢之後 dis 數組為:

繼續在剩下的 5 和 6 號頂點中,選出離 1 號頂點最近的頂點,這次選擇 5 號頂點。此時,dis[5]的值已經從「估計值」變為了「確定值」。對5號頂點的所有出邊(5->4)進行鬆弛。鬆弛完畢之後 dis 數組為:

最後對 6 號頂點的所有出邊進行鬆弛。因為這個例子中 6 號頂點沒有出邊,因此不用處理。 到此,dis 數組中所有的值都已經從「估計值」變為了「確定值」。

最終 dis 數組如下,這便是 1 號頂點到其餘各個頂點的最短路徑。

OK,現在來總結一下剛才的演算法。 Dijkstra演算法的基本思想是:每次找到離源點(上面例子的源點就是 1 號頂點)最近的一個頂點,然後以該頂點為中心進行擴展,最終得到源點到其餘所有點的最短路徑。

基本步驟如下:

在 博客 中看到兩個比較有趣的問題,也是在學習Dijkstra時,可能會有疑問的問題。

當我們看到上面這個圖的時候,憑借多年對平面幾何的學習,會發現在「三角形ABC」中,滿足不了 構成三角形的條件(任意兩邊之和大於第三邊)。 納尼,那為什麼圖中能那樣子畫?

還是「三角形ABC」,以A為起點,B為終點,如果按照平面幾何的知識, 「兩點之間線段最短」, 那麼,A到B的最短距離就應該是6(線段AB),但是,實際上A到B的最短距離卻是3+2=5。這又怎麼解釋?

其實,之所以會有上面的疑問,是因為 對邊的權值和邊的長度這兩個概念的混淆, 。之所以這樣畫,也只是為了方便理解(每個人寫草稿的方式不同,你完全可以用別的方式表示,只要便於你理解即可)。

PS:數組實現鄰接表可能較難理解,可以看一下 這里

參考資料:

Dijkstra演算法是一種基於貪心策略的演算法。每次新擴展一個路程最短的點,更新與其相鄰的點的路程。當所有邊權都為正時,由於不會存在一個路程更短的沒擴展過的點,所以這個點的路程永遠不會再被改變,因而保證了演算法的正確性。

根據這個原理, 用Dijkstra演算法求最短路徑的圖不能有負權邊, 因為擴展到負權邊的時候會產生更短的路徑,有可能破壞了已經更新的點路徑不會發生改變的性質。

那麼,有沒有可以求帶負權邊的指定頂點到其餘各個頂點的最短路徑演算法(即「單源最短路徑」問題)呢?答案是有的, Bellman-Ford演算法 就是一種。(我們已經知道了 Floyd-Warshall 可以解決「多源最短路」問題,也要求圖的邊權均為正)

通過 鄰接矩陣 的Dijkstra時間復雜度是 。其中每次找到離 1 號頂點最近的頂點的時間復雜度是 O(N),這里我們可以用 優先隊列(堆) 來優化,使得這一部分的時間復雜度降低到 。這個我們將在後面討論。

⑤ djstl演算法

定義Dijkstra(迪傑斯特拉)演算法是典型的單源最短路徑演算法,用於計算一個節點到其他所有節點的最短路徑。主要特點是以起始點為中心向外層層擴展,直到擴展到終點為止。Dijkstra演算法是很有代表性的最短路徑演算法,在很多專業課程中都作為基本內容有詳細的介紹,如數據結構,圖論,運籌學等等。Dijkstra一般的表述通常有兩種方式,一種用永久和臨時標號方式,一種是用OPEN,
CLOSE表的方式,這里均採用永久和臨時標號的方式。注意該演算法要求圖中不存在負權邊。
問題描述在無向圖
G=(V,E) 中,假設每條邊 E[i] 的長度為 w[i],找到由頂點 V0 到其餘各點的最短路徑。(單源最短路徑)

編輯本段迪傑斯特拉演算法迪傑斯特拉(Dijkstra)演算法思想
按路徑長度遞增次序產生最短路徑演算法:

把V分成兩組:

(1)S:已求出最短路徑的頂點的集合

(2)V-S=T:尚未確定最短路徑的頂點集合

將T中頂點按最短路徑遞增的次序加入到S中,

保證:(1)從源點V0到S中各頂點的最短路徑長度都不大於

從V0到T中任何頂點的最短路徑長度

(2)每個頂點對應一個距離值

S中頂點:從V0到此頂點的最短路徑長度

T中頂點:從V0到此頂點的只包括S中頂點作中間

頂點的最短路徑長度

依據:可以證明V0到T中頂點Vk的最短路徑,或是從V0到Vk的

直接路徑的權值;或是從V0經S中頂點到Vk的路徑權值之和

(反證法可證)

求最短路徑步驟
演算法步驟如下:

1. 初使時令 S={V0},T={其餘頂點},T中頂點對應的距離值

若存在<V0,Vi>,d(V0,Vi)為<V0,Vi>弧上的權值

若不存在<V0,Vi>,d(V0,Vi)為∝

2. 從T中選取一個其距離值為最小的頂點W且不在S中,加入S

3. 對S中頂點的距離值進行修改:若加進W作中間頂點,從V0到Vi的

距離值縮短,則修改此距離值

重復上述步驟2、3,直到S中包含所有頂點,即W=Vi為止

編輯本段迪傑斯特拉演算法的原理首先,引進一個輔助向量D,它的每個分量D表示當前所找到的從始點v到每個終點vi的最短路徑的長度。如D[3]=2表示從始點v到終點3的路徑相對最小長度為2。這里強調相對就是說在演算法過程中D的值是在不斷逼近最終結果但在過程中不一定就等於最短路徑長度。它的初始狀態為:若從v到vi有弧,則D為弧上的權值;否則置D為∞。顯然,長度為
D[j]=Min{D | vi∈V} 的路徑就是從v出發的長度最短的一條最短路徑。此路徑為(v,vj)。
那麼,下一條長度次短的最短路徑是哪一條呢?假設該次短路徑的終點是vk,則可想而知,這條路徑或者是(v,vk),或者是(v,vj,vk)。它的長度或者是從v到vk的弧上的權值,或者是D[j]和從vj到vk的弧上的權值之和。
一般情況下,假設S為已求得最短路徑的終點的集合,則可證明:下一條最短路徑(設其終點為X)或者是弧(v,x),或者是中間只經過S中的頂點而最後到達頂點X的路徑。因此,下一條長度次短的最短路徑的長度必是D[j]=Min{D
| vi∈V-S} 其中,D或者是弧(v,vi)上的權值,或者是D[k](vk∈S)和弧(vk,vi)上的權值之和。 迪傑斯特拉演算法描述如下:
1)arcs表示弧上的權值。若不存在,則置arcs為∞(在本程序中為MAXCOST)。S為已找到從v出發的最短路徑的終點的集合,初始狀態為空集。那麼,從v出發到圖上其餘各頂點vi可能達到的最短路徑長度的初值為D=arcs[Locate
Vex(G,v),i] vi∈V 2)選擇vj,使得D[j]=Min{D | vi∈V-S} 3)修改從v出發到集合V-S上任一頂點vk可達的最短路徑長度。

編輯本段迪傑斯特拉演算法C#程序public class Edge

{

public string StartNodeID ;

public string EndNodeID ;

public double Weight ; //權值,代價

} 節點則抽象成Node類,一個節點上掛著以此節點作為起點的「出邊」表。

public class Node

{

private string iD ;

private ArrayList edgeList ;//Edge的集合--出邊表

public Node(string id )

{

this.iD = id ;

this.edgeList = new ArrayList() ;

}

property#region property

public string ID

{

get

{

return this.iD ;

}

}

public ArrayList EdgeList

{

get

{

return this.edgeList ;

}

}

#endregion

}

在計算的過程中,我們需要記錄到達每一個節點權值最小的路徑,這個抽象可以用PassedPath類來表示:

/// <summary>

/// PassedPath 用於緩存計算過程中的到達某個節點的權值最小的路徑

/// </summary>

public class PassedPath

{

private string curNodeID ;

private bool beProcessed ; //是否已被處理

private double weight ; //累積的權值

private ArrayList passedIDList ; //路徑

public PassedPath(string ID)

{

this.curNodeID = ID ;

this.weight = double.MaxValue ;

this.passedIDList = new ArrayList() ;

this.beProcessed = false ;

}

#region property

public bool BeProcessed

{

get

{

return this.beProcessed ;

}

set

{

this.beProcessed = value ;

}

}

public string CurNodeID

{

get

{

return this.curNodeID ;

}

}

public double Weight

{

get

{

return this.weight ;

}

set

{

this.weight = value ;

}

}

public ArrayList PassedIDList

{

get

{

return this.passedIDList ;

}

}

#endregion

}

另外,還需要一個表PlanCourse來記錄規劃的中間結果,即它管理了每一個節點的PassedPath。

/// <summary>

/// PlanCourse 緩存從源節點到其它任一節點的最小權值路徑=》路徑表

/// </summary>

public class PlanCourse

{

private Hashtable htPassedPath ;

#region ctor

public PlanCourse(ArrayList nodeList ,string originID)

{

this.htPassedPath = new Hashtable() ;

Node originNode = null ;

foreach(Node node in nodeList)

{

if(node.ID == originID)

{

originNode = node ;

}

else

{

PassedPath pPath = new PassedPath(node.ID) ;

this.htPassedPath.Add(node.ID ,pPath) ;

}

}

if(originNode == null)

{

throw new Exception("The origin node is not exist !")
;

}

this.InitializeWeight(originNode) ;

}

private void InitializeWeight(Node originNode)

{

if((originNode.EdgeList == null)
||(originNode.EdgeList.Count == 0))

{

return ;

}

foreach(Edge edge in originNode.EdgeList)

{

PassedPath pPath = this[edge.EndNodeID] ;

if(pPath == null)

{

continue ;

}

pPath.PassedIDList.Add(originNode.ID) ;

pPath.Weight = edge.Weight ;

}

}

#endregion

public PassedPath this[string nodeID]

{

get

{

return (PassedPath)this.htPassedPath[nodeID] ;

}

}

}

在所有的基礎構建好後,路徑規劃演算法就很容易實施了,該演算法主要步驟如下:

(1)用一張表(PlanCourse)記錄源點到任何其它一節點的最小權值,初始化這張表時,如果源點能直通某節點,則權值設為對應的邊的權,否則設為double.MaxValue。

(2)選取沒有被處理並且當前累積權值最小的節點TargetNode,用其邊的可達性來更新到達其它節點的路徑和權值(如果其它節點
經此節點後權值變小則更新,否則不更新),然後標記TargetNode為已處理。

(3)重復(2),直至所有的可達節點都被處理一遍。

(4)從PlanCourse表中獲取目的點的PassedPath,即為結果。

下面就來看上述步驟的實現,該實現被封裝在RoutePlanner類中:

/// <summary>

/// RoutePlanner 提供圖演算法中常用的路徑規劃功能。

/// 2005.09.06

/// </summary>

public class RoutePlanner

{

public RoutePlanner()

{

}

#region Paln

//獲取權值最小的路徑

public RoutePlanResult Paln(ArrayList nodeList ,string
originID ,string destID)

{

PlanCourse planCourse = new PlanCourse(nodeList
,originID) ;

Node curNode = this.GetMinWeightRudeNode(planCourse
,nodeList ,originID) ;

#region 計算過程

while(curNode != null)

{

PassedPath curPath = planCourse[curNode.ID] ;

foreach(Edge edge in curNode.EdgeList)

{

PassedPath targetPath = planCourse[edge.EndNodeID] ;

double tempWeight = curPath.Weight + edge.Weight ;

if(tempWeight < targetPath.Weight)

{

targetPath.Weight = tempWeight ;

targetPath.PassedIDList.Clear() ;

for(int i=0 ;i<curPath.PassedIDList.Count ;i++)

{

targetPath.PassedIDList.Add(curPath.PassedIDList.ToString())
;

}

targetPath.PassedIDList.Add(curNode.ID) ;

}

}

//標志為已處理

planCourse[curNode.ID].BeProcessed = true ;

//獲取下一個未處理節點

curNode = this.GetMinWeightRudeNode(planCourse
,nodeList ,originID) ;

}

#endregion

//表示規劃結束

return this.GetResult(planCourse ,destID) ;

}

#endregion

#region private method

#region GetResult

//從PlanCourse表中取出目標節點的PassedPath,這個PassedPath即是規劃結果

private RoutePlanResult GetResult(PlanCourse
planCourse ,string destID)

{

PassedPath pPath = planCourse[destID] ;

if(pPath.Weight == int.MaxValue)

{

RoutePlanResult result1 = new RoutePlanResult(null
,int.MaxValue) ;

return result1 ;

}

string[] passedNodeIDs = new
string[pPath.PassedIDList.Count] ;

for(int i=0 ;i<passedNodeIDs.Length ;i++)

{

passedNodeIDs = pPath.PassedIDList.ToString() ;

}

RoutePlanResult result = new
RoutePlanResult(passedNodeIDs ,pPath.Weight) ;

return result ;

}

#endregion

#region GetMinWeightRudeNode

//從PlanCourse取出一個當前累積權值最小,並且沒有被處理過的節點

private Node GetMinWeightRudeNode(PlanCourse
planCourse ,ArrayList nodeList ,string originID)

{

double weight = double.MaxValue ;

Node destNode = null ;

foreach(Node node in nodeList)

{

if(node.ID == originID)

{

continue ;

}

PassedPath pPath = planCourse[node.ID] ;

if(pPath.BeProcessed)

{

continue ;

}

if(pPath.Weight < weight)

{

weight = pPath.Weight ;

destNode = node ;

}

}

return destNode ;

}

#endregion

#endregion

}

編輯本段迪傑斯特拉演算法pascal程序type bool=array[1..10]of
boolean;

arr=array[0..10]of integer;

var a:array[1..10,1..10]of integer;
//存儲圖的鄰接數組,無邊為10000

c,d,e:arr; //c為最短路徑數值,d為各點前趨,

t:bool; //e:路徑,t為輔助數組

i,j,n,m:integer;

inf,outf:text;

////////////////////////////////////////////////////////////////////////////////

procere init; //不同題目鄰接數組建立方式不一樣

begin

assign(inf,'dijkstra.in');
assign(outf,'dijkstra.out');

reset(inf); rewrite(outf);

read(inf,n);

for i:=1 to n do

for j:=1 to n do

begin

read(inf,a[i,j]);

if a[i,j]=0 then a[i,j]:=10000;

end;

end;

////////////////////////////////////////////////////////////////////////////////

procere dijkstra(qi:integer; t:bool; var c{,d}:arr);
//qi起點,{}中為求路徑部

var i,j,k,min:integer; //分,不需求路徑時可以不要

begin //t數組一般在調用前初始

t[qi]:=true; //化成false,也可將部分點

{for i:=1 to n do d[i]:=qi; d[qi]:=0; }
//初始化成true以迴避這些點

for i:=1 to n do c[i]:=a[qi,i];

for i:=1 to n-1 do

begin

min:=10001;

for j:=1 to n do

if (c[j]<min)and(not(t[j])) then begin k:=j;
min:=c[j];end;

t[k]:=true;

for j:=1 to n do

if (c[k]+a[k,j]<c[j])and(not(t[j])) then

begin

c[j]:=c[k]+a[k,j]; {d[j]:=k;}

end;

end;

end;

////////////////////////////////////////////////////////////////////////////////

procere make(zh:integer; d:arr; var e:arr);
//生成路徑,e[0]保存路徑

var i,j,k:integer; //上的節點個數

begin

i:=0;

while d[zh]<>0 do

begin

inc(i);e[i]:=zh;zh:=d[zh];

end;

inc(i);e[i]:=qi; e[0]:=I;

end;

主程序調用:求最短路徑長度:初始化t,然後dijkstra(qi,t,c,d)

求路徑:make(m,d,e) ,m是終點

編輯本段Dijkstra演算法的堆優化(PASCAL實現)一、思考
我們可以發現,在實現步驟時,效率較低(需要O(n),使總復雜度達到O(n^2)。對此可以考慮用堆這種數據結構進行優化,使此步驟復雜度降為O(log(n))(總復雜度降為O(n
log(n))。

二、實現
1. 將與源點相連的點加入堆,並調整堆。
2. 選出堆頂元素u(即代價最小的元素),從堆中刪除,並對堆進行調整。
3. 處理與u相鄰的,未被訪問過的,滿足三角不等式的頂點
1):若該點在堆里,更新距離,並調整該元素在堆中的位置。
2):若該點不在堆里,加入堆,更新堆。
4. 若取到的u為終點,結束演算法;否則重復步驟2、3。
三、代碼
procere Dijkstra;

var

u,v,e,i:longint;

begin

fillchar(dis,sizeof(dis),$7e); //距離

fillchar(Inh,sizeof(Inh),false); //是否在堆中

fillchar(visit,sizeof(visit),false); //是否訪問過

size:=0;

e:=last[s];

while e<>0 do //步驟1

begin

u:=other[e];

if not(Inh[u]) then //不在堆里

begin

inc(size);

heap[size]:=u;

dis[u]:=cost[e];

Loc[u]:=size; //Loc數組記錄元素在堆中的位置

Inh[u]:=true;

Shift_up(Loc[u]); //上浮

end

else

if cost[e]<dis[u] then //在堆里

begin

dis[u]:=cost[e];

Shift_up(Loc[u]);

Shift_down(Loc[u]);

end;

e:=pre[e];

end;

visit[s]:=true;

while true do

begin

u:=heap[1]; //步驟2

if u=t then break; //步驟4

visit[u]:=true;

heap[1]:=heap[size];

dec(size);

Shift_down(1);

e:=last[u];

while e<>0 do //步驟3

begin

v:=other[e];

if Not(visit[v]) and (dis[u]+cost[e]<dis[v]) then
//與u相鄰的,未被訪問過的,滿足三角不等式的頂點

if Inh[v] then //在堆中

begin

dis[v]:=dis[u]+cost[e];

Shift_up(Loc[v]);

Shift_Down(Loc[v]);

end

else //不再堆中

begin

inc(size);

heap[size]:=v;

dis[v]:=dis[u]+cost[e];

Loc[v]:=size;

Inh[v]:=true;

Shift_up(Loc[v]);

end;

e:=pre[e];

end;

end;

writeln(dis[t]);

end;
http://ke..com/view/7839.htm

http://ke..com/view/1939816.htm

熱點內容
內置存儲卡可以拆嗎 發布:2025-05-18 04:16:35 瀏覽:330
編譯原理課時設置 發布:2025-05-18 04:13:28 瀏覽:371
linux中進入ip地址伺服器 發布:2025-05-18 04:11:21 瀏覽:606
java用什麼軟體寫 發布:2025-05-18 03:56:19 瀏覽:27
linux配置vim編譯c 發布:2025-05-18 03:55:07 瀏覽:100
砸百鬼腳本 發布:2025-05-18 03:53:34 瀏覽:935
安卓手機如何拍視頻和蘋果一樣 發布:2025-05-18 03:40:47 瀏覽:729
為什麼安卓手機連不上蘋果7熱點 發布:2025-05-18 03:40:13 瀏覽:798
網卡訪問 發布:2025-05-18 03:35:04 瀏覽:505
接收和發送伺服器地址 發布:2025-05-18 03:33:48 瀏覽:367