日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

图的最短路径--单源、多源最短路径

發(fā)布時(shí)間:2024/5/14 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 图的最短路径--单源、多源最短路径 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

最短路徑

–在網(wǎng)絡(luò)中,求兩個(gè)不同頂點(diǎn)之間的所有路徑中,邊的權(quán)值之和最小的路勁。

單源最短路徑

–從某固定源點(diǎn)出發(fā)的最短路徑

無(wú)權(quán)圖的最短路徑
  • 按照路徑長(zhǎng)度遞增的順序找出源點(diǎn)到各個(gè)頂點(diǎn)的最短路徑

  • 類(lèi)似于BFS-寬度優(yōu)先遍歷,可以通過(guò)隊(duì)列來(lái)實(shí)現(xiàn),

    • 先讓頂點(diǎn)入隊(duì),循環(huán)執(zhí)行下列步驟
    • 出隊(duì)首元素,訪問(wèn)其所有鄰接點(diǎn)
    • 標(biāo)明源點(diǎn)到這些鄰接點(diǎn)的路徑長(zhǎng)度,并將其入隊(duì)
有權(quán)圖的最短路徑
Dijkstra算法
  • 令第一組為集合S={源點(diǎn)+已經(jīng)確定最短路徑的頂點(diǎn)vi}

  • 令第二組為未在集合S中的頂點(diǎn)v,定義length成員為源點(diǎn)s到v的最短路徑長(zhǎng)度,該路徑除了終點(diǎn)v以外,所有頂點(diǎn)都必須是集合S中的頂點(diǎn)。即{s—>(vi∈S)—>v}的最小長(zhǎng)度

  • 每次對(duì)未在第一組集合S的頂點(diǎn),選一個(gè)length最小的頂點(diǎn)(記為v),將其增加至集合S中。

    • 如何選這個(gè)頂點(diǎn)V–用一個(gè)最小堆H(剛開(kāi)始只有源點(diǎn)),每次找出并刪除一個(gè)length值最小的頂點(diǎn)V,這里這個(gè)找到并刪除的頂點(diǎn)V就是每次加入集合S的頂點(diǎn),然后找到V的所有鄰接點(diǎn),對(duì)其鄰接點(diǎn)的length值進(jìn)行賦值,然后加入最小堆H里,往復(fù)循環(huán),直至最小堆空了(最小堆空了,即所有頂點(diǎn)都加入了集合S)–看程序就明白了

    • 選進(jìn)去的時(shí)候要注意什么–增加v進(jìn)集合S中會(huì)影響頂點(diǎn)w(w為v的鄰接點(diǎn))的length值,因?yàn)槎嗔藗€(gè)頂點(diǎn)v,可能會(huì)改變s—w的走法,原先不經(jīng)過(guò)v,現(xiàn)在最短路徑經(jīng)過(guò)v,即需要考慮

      length[w],與length[v] + e.weigth的大小關(guān)系--------(1)

  • 直到把所有頂點(diǎn)都送進(jìn)集合S中

設(shè)源點(diǎn)為V0,則按照Dijkstra算法的最短路徑求解過(guò)程如下

注:初始的時(shí)候只有集合S只有源點(diǎn)s,因此只有到點(diǎn)v1、v2有路徑,路徑長(zhǎng)度用length表示,,沒(méi)有路徑則length為∞,路徑的終點(diǎn)的前一個(gè)點(diǎn)用pre表示。

```C++ class Dist { // Dist類(lèi),用于保存最短路徑信息public:int index; // 結(jié)點(diǎn)的索引值int length; // 當(dāng)前最短路徑長(zhǎng)度int pre; // 路徑最后經(jīng)過(guò)的結(jié)點(diǎn) };void Dijkstra(Graph& G, int s, Dist* &D) { // s是源點(diǎn)D = new Dist[G. VerticesNum()]; // 開(kāi)辟空間給類(lèi)Dist,用來(lái)記錄當(dāng)前最短路徑長(zhǎng)度for (int i = 0; i < G.VerticesNum(); i++) { // 初始化,將圖中所有頂點(diǎn)的標(biāo)志位記為未訪問(wèn),將Dist類(lèi)的索引值記為頂點(diǎn)號(hào),將頂點(diǎn)到源點(diǎn)的length置為∞。G.Mark[i] = UNVISITED; D[i].index = i; D[i].length = INFINITE;D[i].pre = s;}D[s].length = 0; // 初始化,源點(diǎn)自身的路徑長(zhǎng)度置為0MinHeap<Dist> H(G. EdgesNum()); // 最小堆用于找出集合S中到源點(diǎn)的路徑最短的點(diǎn),最小堆存放Dist類(lèi)元素,共有G.EdgesNum個(gè)長(zhǎng)度H.Insert(D[s]); //將源點(diǎn)放入最小堆for (i = 0; i < G.VerticesNum(); i++) {bool FOUND = false;Dist d;while (!H.isEmpty()) {d = H.RemoveMin(); //獲得集合S中到源點(diǎn)s路徑長(zhǎng)度最小的結(jié)點(diǎn),并刪除if (G.Mark[d.index] == UNVISITED) { //如果未訪問(wèn)過(guò)則跳出循環(huán)FOUND = true; break;} }if (!FOUND) break; // 若沒(méi)有符合條件的最短路徑則跳出本次循環(huán)int v = d.index; G.Mark[v] = VISITED; // 將標(biāo)記位設(shè)置為 VISITEDfor (Edge e = G.FirstEdge(v); G.IsEdge(e); e = G.NextEdge(e)) // 對(duì)最小堆中到源點(diǎn)路徑最短的頂點(diǎn)v,求他的每個(gè)鄰接點(diǎn),并考慮是否需要改變其最小距離--刷新最短路,然后將其加入最小堆if (D[G.ToVertex(e)].length > (D[v].length+G.Weight(e))) {//這里第一次執(zhí)行時(shí),因?yàn)閯傞_(kāi)始最小堆里只有源點(diǎn),其他頂點(diǎn)到源點(diǎn)的length都為∞,執(zhí)行完后V1、V2的length值才改變D[G.ToVertex(e)].length = D[v].length + G.Weight(e);D[G.ToVertex(e)].pre = v;H.Insert(D[G.ToVertex(e)]);} } }

Dijkstra算法時(shí)間復(fù)雜度

T = O ( ∣ V ∣ l o g ∣ V ∣ + ∣ E ∣ l o g ∣ V ∣ ) = O ( ∣ E ∣ l o g ∣ V ∣ ) T = O( |V| log|V| + |E| log|V| ) = O( |E| log|V| ) T=O(VlogV+ElogV)=O(ElogV)

前半部分為在最小堆里找V次,依次復(fù)雜度為logV,后半部分是往最小堆里插入Dist,一次最多有可能插E次(極限情況,一個(gè)頂點(diǎn)有E條邊)

Dijkstra使用條件
  • 圖中不能出現(xiàn)有總權(quán)值為負(fù)值的回路
  • 如果存在負(fù)值邊也有可能發(fā)生計(jì)算錯(cuò)誤
  • 持負(fù)權(quán)值的最短路徑算法有Ford算法、SPFA算法

多源最短路徑

–求每對(duì)頂點(diǎn)間的最短路徑

Floyd算法
  • Dk[i] [j]表示路徑{ i —> { l<= k } —> j }的最小長(zhǎng)度(i、j、l、k表示頂點(diǎn)編號(hào))

  • 首先用矩陣D0表示該圖的鄰接矩陣

  • 在矩陣D0上做n次迭代

  • 如何迭代呢–當(dāng)Dk-1已經(jīng)完成,遞推到Dk時(shí),

    • 若k?最短路徑{ i —> { l<= k } —> j },(即i到j(luò)的最短路徑不經(jīng)過(guò)k)則Dk=Dk-1

    • 若k∈最短路徑{ i —> { l<= k } —> j }(即i到j(luò)的最短路徑經(jīng)過(guò)k),則該最短路徑由兩條路徑組成:
      D ( k ) [ i ] [ j ] = D ( k ? 1 ) [ i ] [ k ] + D ( k ? 1 ) [ k ] [ j ] D(k)[i][j]=D(k-1)[i][k]+D(k-1)[k][j] D(k)[i][j]=D(k?1)[i][k]+D(k?1)[k][j]

cpp void Floyd(Graph& G, Dist** &D) {int i,j,v;D = new Dist*[G.VerticesNum()]; // 申請(qǐng)空間,申請(qǐng)一個(gè)與鄰接矩陣等大的Dfor (i = 0; i < G.VerticesNum(); i++)D[i] = new Dist[G.VerticesNum()];// 初始化數(shù)組Dfor (i = 0; i < G.VerticesNum(); i++) for (j = 0; j < G.VerticesNum(); j++) {if (i == j) { D[i][j].length = 0;D[i][j].pre = i; }else { D[i][j].length = INFINITE; D[i][j].pre = -1; } }//對(duì)D0矩陣進(jìn)行賦值,讓其與鄰接矩陣相同for (v = 0; v < G.VerticesNum(); v++)for (Edge e = G.FirstEdge(v); G.IsEdge(e); e = G.NextEdge(e)) {D[v][G.ToVertex(e)].length = G.Weight(e);D[v][G.ToVertex(e)].pre = v; }// 加入新結(jié)點(diǎn)后,更新那些變短的路徑長(zhǎng)度for (k = 0; k< G.VerticesNum(); k++)for (i = 0; i < G.VerticesNum(); i++)for (j = 0; j < G.VerticesNum(); j++)if (D[i][j].length > (D[i][k].length+D[k][j].length)) {D[i][j].length = D[i][k].length+D[k][j].length; D[i][j].pre = D[k][j].pre;//第k次迭代,考慮在加入編號(hào)為k的頂點(diǎn)的情況下,是否需要更新i、j之間的路徑長(zhǎng)度} }
Floyd算法時(shí)間復(fù)雜度

T = O ( ∣ V ∣ 3 ) T = O( |V|3 ) T=O(V3)

總結(jié)

以上是生活随笔為你收集整理的图的最短路径--单源、多源最短路径的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。