国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

dijkstra算法:堆優(yōu)化 + 輸出所有最短路徑(得到所有最優(yōu)解)

這篇具有很好參考價值的文章主要介紹了dijkstra算法:堆優(yōu)化 + 輸出所有最短路徑(得到所有最優(yōu)解)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

改進迪杰斯特拉算法(dijkstra):輸出所有最短路徑

對于權值非負的圖求解單源最短路徑,第一想法是使用dijkstra算法。最短路徑問題是滿足最優(yōu)子結構的:父問題一定會使用子問題的最優(yōu)解。問題在于子問題的計算次序。dijkstra算法思想建立在我們?yōu)闊o負權圖定義的子問題計算順序基礎上:即離源點最近點不會變成其他問題的子問題,其他問題只能成為他的子問題。

?本次實驗在實現dijkstra算法的基礎上:

  • 構建基于鄰接表的圖類:Graph.class,便于以后實驗復用。
  • 此外加入了優(yōu)先隊列進行優(yōu)化
  • 不僅實現對最優(yōu)解(最短路徑)的記錄而且對所有的最優(yōu)解(所有的最短路徑)進行輸出

本次實現額外實現部分:

  • 實現基于鄰接表的Graph數據結構
  • 堆優(yōu)化:將時間復雜度優(yōu)化到 n l g ( n ) nlg(n) nlg(n)
  • 輸出【所有的最短路徑】:需要花費額外的時間復雜度(一般的dijkstra不需要輸出所有的最短路徑,只需要輸出一條,本實驗輸出了所有的最短路徑)

程序如下:

//
// Created by BlancheSun on 2022/4/10.
//

#include<iostream>
#include<algorithm>
#include <vector>
#include <queue>

using namespace std;

class ArcNode{
public:
    int adjvec;
    double weight;
    ArcNode(int adjvec, double weight) : adjvec(adjvec), weight(weight){};
    ArcNode() {};
    friend bool operator<(const ArcNode& arc1, const ArcNode& arc2) {
        return arc1.weight > arc2.weight;
    }
};

class Graph{
private:
    int vexnum; // 頂點數
    int arcnum; // 邊數
    vector<vector<ArcNode>> arcList;   // 矩陣存儲結點之間的連接關系
public:
    Graph(int vexnum, int arcnum);
    Graph();
    void add_edge(int start, int end, double weight);
    void dijkstra(int source, int target);
    void recordShortestPath(vector<vector<int>>& pre, int target, vector<vector<int>>& path, vector<int> temp_path);
    void printAllPath(vector<vector<int>>& path, vector<double>& dis, int source, int target);
};

void Graph::add_edge(int start, int end, double weight){
    arcList[start].push_back(ArcNode(end, weight));
    arcList[end].push_back(ArcNode(start, weight));
}

void Graph::dijkstra(int source, int target) {
    // 初始化操作
    int n = this->vexnum;
    int inf = 99999.0;
    vector<double> dis(n, inf);
    dis[source] = 0;
    vector<vector<int>> pre(n,vector<int>(0));
    priority_queue<ArcNode> nodeQueue;
    nodeQueue.push(ArcNode(source, 0));

    // 隊列非空時進行檢索
    while(!nodeQueue.empty()) {
        int node = nodeQueue.top().adjvec;  // 獲得目前隊列中距離源點最近的結點
        double weight = nodeQueue.top().weight;  // 或者寫成 weight = nodeQueue.top().weight
        nodeQueue.pop();    // 取出隊列中的元素

        if(node == 3||node == 5) {
            int m = 1;
        }
        // 從該結點出發(fā),更新該結點能直接相連的結點
        for(int i = 0; i < arcList[node].size(); i++) {
            int v = arcList[node][i].adjvec;
            if (weight + arcList[node][i].weight < dis[v]) {    // 越界了!
                dis[v] = weight + arcList[node][i].weight;
                pre[v] = {node};                          // 記錄上一步的結點
                nodeQueue.push(ArcNode(v, dis[v]));
            }else if(weight + arcList[node][i].weight == dis[v]) {
                pre[v].push_back(node);
            }
        }
    }
    vector<vector<int>> path;    // 初始大小的為0,
    vector<int> temp_path;
    recordShortestPath(pre, target, path, temp_path);   // 運行后path_index數值即為路徑條數,不用加一,程序中已經加一
    printAllPath(path, dis, source, target);

}

Graph::Graph(int vexnum, int arcnum) : vexnum(vexnum), arcnum(arcnum) {
    // 做容量的初始化
    vector<vector<ArcNode>> V(vexnum, vector<ArcNode>());
    this->arcList = V;
}

Graph::Graph() {}

/** 第k條路徑的記錄 **/
void Graph::recordShortestPath(vector<vector<int>> &pre, int target, vector<vector<int>>& path, vector<int> temp_path) {
    vector<int> now_pre = pre[target];  // 獲得當前節(jié)點的前驅結點集合
    temp_path.push_back(target);
    if(now_pre.empty()) {   // 沒有前驅結點
        path.push_back(temp_path);
        return;
    }
    // 不為空,那么深搜前驅結點,得到路徑
    for(int i = 0; i < now_pre.size(); i++) {
        int target2 = now_pre[i];   // 集合中的一個點
        recordShortestPath(pre, target2, path, temp_path);
    }
}

/** 打印所有的路徑 **/
void Graph::printAllPath(vector<vector<int>> &path, vector<double>& dis, int source, int target) {
    cout << "The shortest path(es) from node " << source << " to node " << target << " are/is as follows: " << endl;
    int k = path.size();    // 路徑的條數
    for(int i = 0; i<k; i++) {
        cout << "Path" << i << ": " ;
        for(int j = path[i].size()-1; j > 0 ; j--) {
            cout << path[i][j] << " -> ";
        }
        cout << path[i][0] << endl;
    }
    cout << "The length of path(es) is " << dis[target] <<endl;
}

int main() {
	// 多條最短路徑的測試
    Graph graph = Graph(9, 14); // 9個頂點,14條邊

    // 邊的添加
    graph.add_edge(0,1,1);
    graph.add_edge(0,7,8);
    graph.add_edge(1,2,8);
    graph.add_edge(1,7,11);
    graph.add_edge(2,3,3);
    graph.add_edge(2,5,4);
    graph.add_edge(2,8,2);
    graph.add_edge(3,4,9);
    graph.add_edge(3,5,1);
    graph.add_edge(4,5,10);
    graph.add_edge(5,6,2);
    graph.add_edge(6,7,1);
    graph.add_edge(6,8,6);
    graph.add_edge(7,8,7);

    int source = 0, target = 4;
    graph.dijkstra(source, target);
    
//    Graph graph = Graph(16, 30); // 16個頂點,30條邊
//
//    // 邊的添加
//    graph.add_edge(0,2,3);
//    graph.add_edge(1,3,1);
//    graph.add_edge(1,4,3);
//    graph.add_edge(1,5,6);
//    graph.add_edge(2,4,8);
//    graph.add_edge(2,5,7);
//    graph.add_edge(2,6,6);
//    graph.add_edge(3,7,6);
//    graph.add_edge(3,8,8);
//    graph.add_edge(4,7,3);
//    graph.add_edge(4,8,5);
//    graph.add_edge(5,8,3);
//    graph.add_edge(5,9,3);
//    graph.add_edge(6,8,8);
//    graph.add_edge(6,9,4);
//    graph.add_edge(7,10,2);
//    graph.add_edge(7,11,2);
//    graph.add_edge(8,11,1);
//    graph.add_edge(8,12,2);
//    graph.add_edge(9,11,3);
//    graph.add_edge(9,12,3);
//    graph.add_edge(10,13,3);
//    graph.add_edge(10,14,5);
//    graph.add_edge(11,13,5);
//    graph.add_edge(11,14,2);
//    graph.add_edge(12,13,6);
//    graph.add_edge(12,14,6);
//    graph.add_edge(13,15,4);
//    graph.add_edge(14,15,3);
//
//
//    // 求解最短路徑
//    int source = 0, target = 15;
//    graph.dijkstra(source, target);

    return 0;
}

以下圖為例進行執(zhí)行

dijkstra算法:堆優(yōu)化 + 輸出所有最短路徑(得到所有最優(yōu)解)
結果如下:可見所有的最短路徑都被輸出
dijkstra算法:堆優(yōu)化 + 輸出所有最短路徑(得到所有最優(yōu)解)

1. 基于鄰接表的Graph

? 基礎的鄰接矩陣也能作為dijkstra算法的數據結構,但是對于稀疏圖或者結點很多的情況下輸入數據較為復雜且容易超出內存。本次實驗使用鄰接表實現圖的數據結構,主要設置如下:

  • ArcNode.class:鄰接表的表結點。含有表結點的終點編號adjvec和邊權重weight兩個屬性。

  • vector<vector<ArcNode>> ArcList

    • ArcList[i]表示結點i為起點的所有表結點的集合
  • Graph.class

    含有三個屬性:

    • vexnum:結點數
    • arcnum:邊數
    • vector<vector<ArcNode>> ArcList:鄰接表

    含有四個方法:

    • add_edge(int start, int end):向鄰接表中增加表結點

    • dijkstra(int source, int target):計算最短路徑和所有結點的前驅結點集合,以求得所有最短路徑

    • recordShortestPath(vector<vector<int>> &pre, vector<vector<int>>& path:根據dijksra中的前驅結點集合pre,進行深度優(yōu)先搜索,得到所有的最短路徑,存入path數組中。

    • printAllPath(vector<vector<int>> &path):打印所有的最短路徑

2 基本算法思路說明與堆優(yōu)化
(1)基本思路

dikstra算法的核心過程很簡單,主要特點是使用廣度優(yōu)先搜索。算法主要過程如下:

  • 初始化:
    • 集合初始化:設置已松弛集合 T = ? T = ? T=?,和未松弛集合 U = { s 0 , s 1 . . . , s n } U = \{s_0,s_1...,s_n\} U={s0?,s1?...,sn?}全部n個結點。
    • 距離數組初始化:設置有大小為結點個數n的距離數組 v e c t o r < i n t > ? d i s ( n , + ∞ ) vector<int>\ dis(n, +\infty) vector<int>?dis(n,+),另外將 d i s [ s 0 ] dis[s_0] dis[s0?]初始化為0。
  • 循環(huán)n輪:每次擴展擴展使用不在集合 T T T中(在集合 U U U中),且距離源點 s 0 s_0 s0?最近的結點 s k s_k sk?對所有與 s k s_k sk?直接相聯(lián)的結點 s j s_j sj?進行松弛,第一輪時即使用 s 0 s_0 s0?進行松弛。松弛條件為:

{ v i s i t e d [ s j ] = = f a l s e : s j 為被用來松弛過 d i s [ s k ] + w e i g h t ( s k , s j ) < d i s [ s j ] \begin{cases}visited[s_j]==false:s_j為被用來松弛過\\ dis[s_k] + weight(s_k,s_j) < dis[s_j]\end{cases} {visited[sj?]==false:sj?為被用來松弛過dis[sk?]+weight(sk?,sj?)<dis[sj?]?

? 滿足條件即更新 d i s [ s j ] = d i s [ s k ] + w e i g h t ( s k , s j ) dis[s_j] = dis[s_k]+weight(s_k,s_j) dis[sj?]=dis[sk?]+weight(sk?,sj?)。更新完后將 s k s_k sk?加入集合T,從U中移出 s k s_k sk?。

? 從動態(tài)規(guī)劃的角度看,上式也可以理解成動態(tài)規(guī)劃的遞推式。

  • 循環(huán)結束:每個結點都被加入 T T T,此時的 d i s [ n ] dis[n] dis[n]即為最短距離。
(2)堆優(yōu)化

在(1)的步驟二循環(huán)n輪中,每次循環(huán)需要尋找距離源點 s 0 s_0 s0?最近的結點。若是采取循環(huán)掃描一遍的過程,那么dijkstra算法的時間復雜度將會為 O ( n 2 ) O(n^2) O(n2),仔細分析,該過程尋找最近距離的過程有下面的特點:

  • 集合大小是動態(tài)變化的結點
  • 每次從集合中尋找的距離最小的元素,不需要所有的元素有序

符合這樣的特點我們可以用堆進行優(yōu)化。即:

  • ① 將遍歷 d i s [ s k ] dis[s_k] dis[sk?]尋找最小值的過程使用一個優(yōu)先隊列 n o d e Q u e u e nodeQueue nodeQueuetop()pop()操作代替。同時 v i s t e d visted visted數組變得不再需要,因為該結點被 p o p ( ) pop() pop(),下輪更新隊列中將不會存在該結點。
  • ② 每次對松弛對 d i s [ v ] dis[v] dis[v]進行操作時,同時需要向優(yōu)先隊列中減小該結點的 w e i g h t weight weight
3 實現多條最短路徑記錄
3.5.3.1 路徑的記錄

如果只需要記錄一條最短路徑,那么我們在進行松弛操作后用一個數組 p r e [ n ] pre[n] pre[n]記住用于松弛該結點的 s k s_k sk?即可。即:
p r e [ s j ] = s k pre[s_j] = s_k pre[sj?]=sk?
我們這里實現了多條最短路徑的輸出,一維數組不再能滿足我們的要求,我們需要一個二維數組 p r e [ n ] [ m ] pre[n][m] pre[n][m]記錄所有的前驅結點。對于一個結點編號為 i i i的結點,其所有的前驅為 p r e [ i ] pre[i] pre[i]集合中的所有元素。當然,如果最短路徑只有一條,那么 p r e [ i ] pre[i] pre[i]中只有一個元素。

另外,需要存儲多條最短路徑后,在松弛時進行的操作和只輸出一條路徑時不相同:

  • d i s [ s k ] + w e i g h t ( s k , s j ) < d i s [ s j ] dis[s_k] + weight(s_k,s_j) < dis[s_j] dis[sk?]+weight(sk?,sj?)<dis[sj?]

    直接將 p r e [ s j ] pre[s_j] pre[sj?]置為 s k s_k sk?的編號,然后將隊列中修改 s j s_j sj?的權重為 d i s [ s k ] + w e i g h t ( s k , s j ) dis[s_k] + weight(s_k,s_j) dis[sk?]+weight(sk?,sj?),更新 d i s [ s j ] = d i s [ s k ] + w e i g h t ( s k , s j ) dis[s_j] = dis[s_k] + weight(s_k,s_j) dis[sj?]=dis[sk?]+weight(sk?,sj?)

  • d i s [ s k ] + w e i g h t ( s k , s j ) = = d i s [ s j ] dis[s_k] + weight(s_k,s_j) == dis[s_j] dis[sk?]+weight(sk?,sj?)==dis[sj?]

    p r e [ s j ] pre[s_j] pre[sj?]增加 s k s_k sk?的編號

3.1 路徑的輸出

按照上述的方式進行記錄后,我們最終得到的 p r e pre pre數組,為了便于說明,我們給出下面的一個例子:

dijkstra算法:堆優(yōu)化 + 輸出所有最短路徑(得到所有最優(yōu)解)

圖18:pre數組舉例

以圖中的結點4為例,我們給出他的 p r e pre pre數組樹:

dijkstra算法:堆優(yōu)化 + 輸出所有最短路徑(得到所有最優(yōu)解)

圖19:pre數組樹

根據這棵 p r e pre pre數組樹,我們能夠通過深度優(yōu)先遍歷的方式得到從結點4開始到源點0的所有的最短路徑。在深搜過程中我們每得到一條路徑就應該將他存在一個二維的 p a t h path path數組,每一維存儲一條路徑。在得到所有最短路徑后,遍歷 p a t h path path數組的每個元素,每一個元素即是一條路徑的路徑數組,逐條打印出路徑結果即可。文章來源地址http://www.zghlxwxcb.cn/news/detail-403408.html

到了這里,關于dijkstra算法:堆優(yōu)化 + 輸出所有最短路徑(得到所有最優(yōu)解)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯(lián)網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 最短路徑(Dijkstra)算法

    目錄 一、Dijkstra算法 二、核心思路 三、步驟 四、代碼 迪杰斯特拉(Dijkstra)算法是由荷蘭計算機科學家狄克斯特拉于1959年提出的。是尋找從一個頂點到其余各頂點的最短路徑算法,可用來 解決最短路徑問題 。

    2024年02月07日
    瀏覽(24)
  • 圖算法——求最短路徑(Dijkstra算法)

    圖算法——求最短路徑(Dijkstra算法)

    ? ? ? ? 目錄 一、什么是最短路徑 二、迪杰斯特拉(Dijkstra)算法 ?三、應用Dijkstra算法 (1) Dijkstra算法函數分析 ????????求圖的最短路徑在實際生活中有許多應用,比如說在你在一個景區(qū)的某個景點,參觀完后,要怎么走最少的路程到你想參觀的下個景點,這就利用到

    2023年04月15日
    瀏覽(20)
  • 【算法】單源最短路徑算法——Dijkstra算法

    【算法】單源最短路徑算法——Dijkstra算法

    迪杰斯特拉算法(Dijkstra)是由荷蘭計算機科學家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。這是從一個頂點到其余各頂點的最短路徑算法,解決的是有權圖中最短路徑問題。迪杰斯特拉算法主要特點是從起始點開始,采用 貪心算法 的策略, 每次遍歷到始點距離最

    2024年02月05日
    瀏覽(26)
  • Dijkstra算法求最短路

    Dijkstra算法求最短路

    Dijkstra算法的流程如下: 1.初始化dist[1] = 0,其余節(jié)點的dist值為無窮大。 2.找出一個未被標記的、dist[x]最小的節(jié)點x,然后標記節(jié)點x。 3.掃描節(jié)點x的所有出邊(x,y,z),若dist[y] dist[x] + z,則使用dist[x] + z更新dist[y]。 4.重復上述2~3兩個步驟,直到所有的節(jié)點都被標記。 Dijk

    2024年02月06日
    瀏覽(21)
  • 【Dijkstra】最短路算法的一種

    首先,本文默認讀者基本熟悉Dijkstra基本原理 DIjkstra是單源最短路的一種算法。使用數組d[i]來儲存結點i到源點s的最短路徑長度,每次更新d[i]數組后,d[i]中最小的一定是一條最短路徑長度。也就是說每次更新后都能找到一條最短路徑,以下給出證明: 假設d[]數組中當前最小

    2024年02月03日
    瀏覽(19)
  • dijkstra模板及例題(最短路算法)

    dijkstra模板及例題(最短路算法)

    ? ? ? ? 大家好,我是永遇樂金槍魚。圖論和樹論是算法中占比大且非常重要的內容,而且樹論是特殊的圖論,而圖論中最經典的就是求解最短路,而最短路算法是比較廣泛且冗雜的算法,與其相關的有較多的算法,下面我給大家講講常用算法之一——dijkstra算法。 ???博客

    2023年04月08日
    瀏覽(15)
  • 二、搜索與圖論6:Dijkstra 模板題+算法模板(Dijkstra求最短路 I, Dijkstra求最短路 II,1003 Emergency)

    二、搜索與圖論6:Dijkstra 模板題+算法模板(Dijkstra求最短路 I, Dijkstra求最短路 II,1003 Emergency)

    樸素dijkstra算法 對應模板題:Dijkstra求最短路 I 時間復雜是 O(n^2+m):n 表示點數,m 表示邊數 堆優(yōu)化版dijkstra 對應模板題:Dijkstra求最短路 II 時間復雜度 O(mlogn):n 表示點數,m 表示邊數 樹是一種特殊的圖 ,與圖的存儲方式相同。 對于無向圖中的邊ab,存儲兩條有向邊a-b, b-a。

    2024年02月14日
    瀏覽(27)
  • 數據結構--最短路徑 Dijkstra算法

    數據結構--最短路徑 Dijkstra算法

    計算? b e g i n ?點到各個點的最短路 color{red}計算 begin 點到各個點的最短路 計算 ? b e g in ? 點到各個點的最短路 如果是無向圖,可以先把無向圖轉化成有向圖 我們需要2個數組 final[] (標記各頂點是否已找到最短路徑)與 dis[] (最短路徑?度)數組 Dijkstra算法是一種用于

    2024年02月12日
    瀏覽(27)
  • 12.圖論1 最短路之dijkstra算法

    二分圖 判定:染色法。 性質: 可以二著色。 無奇圈。 樹的直徑模板 兩遍dfs/bfs,證明時反證法的核心是用假設推出矛盾。 設1是一開始隨機選的點,s是與其最遠的點,證明s是直徑的一端。 反證:假設s不是直徑的一端,ss是直徑的一端。 現在要做的就是證明ss是直徑的一端

    2024年02月20日
    瀏覽(18)
  • 【圖論算法】最短路徑算法(無權最短路徑、Dijkstra算法、帶負邊值的圖、無圈圖)

    【圖論算法】最短路徑算法(無權最短路徑、Dijkstra算法、帶負邊值的圖、無圈圖)

    本篇博客將考察各種最短路徑問題。 ????無權最短路徑 ????Dijkstra 算法 ????具有負邊值的圖 ????無圈圖 ????所有頂點對間的最短路徑 ????最短路徑的例子–詞梯游戲 輸入是一個賦權圖:與每條邊 (v i , v j ) 相聯(lián)系的是穿越該邊的開銷(或稱為值

    2023年04月12日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包