【算法】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(){
} 

 

posted @ 2017-10-22 23:16  ninding  阅读(2349)  评论(0编辑  收藏  举报