【算法】Dijkstra算法(單源最短路徑問題)(路徑還原) 鄰接矩陣和鄰接表實現


Dijkstra算法可使用的前提:不存在負圈。

負圈:負圈又稱負環,就是說一個全部由負權的邊組成的環,這樣的話不存在最短路,因為每在環中轉一圈路徑總長就會邊小。

 

 

算法描述:

  1.找到最短距離已確定的頂點,從它出發更新相鄰頂點的最短距離。

  2.以后不需要再關心1中的“最短距離已確定的頂點”。

 

 

C++代碼:

#include <bits\stdc++.h>
using namespace std;
#define INF 2147483647
#define MAX_V 1000
#define MAX_E 2000 

//單源最短路徑問題(Dijkstra算法) 


int cost[MAX_V][MAX_V];  //cost[u][v]表示e = (u,v)的權值 
int d[MAX_V];        //頂點s出發的最短距離 
bool used[MAX_V];    //標記使用過的點 
int V;          //頂點數 

void dijkstra(int s){
    fill(d, d+V, INF);
    fill(used, used + V, false);
    d[s] = 0;
    
    while(true){
        int v = -1;
        
        //找到一個距離最近的沒有使用過的點 
        for(int u = 0;u < V; u++){
            if(!used[u] && (v == -1 || d[u] < d[v])) v = u;
        }
        //如果所有的點都被使用過了,則break
        if(v == -1) break;
        
        //標記當前點被使用過了 
        used[v] = true;
        
        //更新這個找到的距離最小的點所連的點的距離 
        for(int u = 0;u < V; u++){
            d[u] = min(d[u], d[v] + cost[v][u]);
        }
        
    }
}


int main(){
} 

 

 

我們會發現,如果邊比較少的話,用鄰接矩陣特別耗時間和空間。

時間復雜度O(V^2)

所以邊比較少的話,有一種鄰接矩陣的寫法,對其優化一下,

時間復雜度O(E*log(V))

 

 

C++代碼:

#include <bits\stdc++.h>
using namespace std;
#define INF 2147483647
#define MAX_V 1000
#define MAX_E 2000 

//單源最短路徑問題(Dijkstra算法) 

struct edge{
    int to,cost;
};    

typedef pair<int, int> P;  //first是最短距離,second是頂點的編號 

int V;    //頂點數 
vector <edge> G[MAX_V];   //
int d[MAX_V];            // d[i]表示i離源點的最短距離 



void dijkstra(int s){
    //通過指定greater<P> 參數,優先隊列是用堆實現的,堆按照first從小到大排序。 
    priority_queue<P, vector<P>, greater<P> > que;
    
    fill(d, d+V, INF);
    d[s] = 0;
    
    //加源點入最小堆 
    que.push(P(0,s));
    
    while(!que.empty()){
        //取出堆頂的點,也就是距離最小的點 
        P p = que.top(); que.pop();
        int v = p.second;
        
        //如果這個點在加入隊列之后更新過,就不必再更新 
        if(d[v] < p.first) continue;
        
        //遍歷當前點相鄰的所有點 
        for(int i = 0;i < G[v].size(); i++){
            edge e = G[v][i];
            //如果這個點能更新其他點,就將被更新的那個點加入隊列。 
            if(d[e.to] > d[v] + e.cost){
                d[e.to] = d[v] + e.cost;
                que.push(P(d[e.to], e.to));
            }    
        }    
    }
}

int main(){
} 

 

 

路徑還原:

#include <bits\stdc++.h>
using namespace std;
#define INF 2147483647
#define MAX_V 1000
#define MAX_E 2000 

//單源最短路徑問題(Dijkstra算法) 


int cost[MAX_V][MAX_V];  //cost[u][v]表示e = (u,v)的權值 
int d[MAX_V];        //頂點s出發的最短距離 
bool used[MAX_V];    //標記使用過的點 
int V;          //頂點數 

int prev[MAX_V];  //最短路徑上的前驅頂點 

void dijkstra(int s){
    fill(d, d+V, INF);
    fill(used, used + V, INF);
    fill(prev, prev+V, -1); //初始化前驅數組 
    d[s] = 0;
    
    while(true){
        int v = -1;
        for(int u = 0;u < V; u++){
            if(!used[u] && (v == -1 || d[u] < d[v])) v = u;
        }
        if(v == -1) break;
        used[v] = true;
        for(int u = 0;u < V; u++){
            d[u] = min(d[u], d[v] + cost[v][u]);
            prev[u] = v;    //記錄每個點的前驅 
        }
    }
}

//獲取起始點到頂點t的最短路徑 
vector <int> getpath(int t){
    vector<int> path;
    while(t != -1){
        path.push_back(t);
        t = prev[t];
    }
    //獲取的路徑是逆序,需要翻轉 
    reverse(path.begin(),path.end());
    
    return path;
}


int main(){
} 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM