1. 程式人生 > >單源最短路徑---Dijkstra算法

單源最短路徑---Dijkstra算法

end mat empty esp mes OS urn struct lse

1、dijkstra算法求解過程:

(1)首先設置兩個頂點集合T和S

  S中存放已找到最短路徑的頂點,初始時,集合S中只有一個頂點,即源點v0

  T中存放當前還未找到最短路徑的頂點

(2)在集合T中選取當前長度最短的一條最短路徑(v0......vk),從而將vk加入到頂點集合S中,並修改遠點v0到T中各個頂點的最短路徑長度;重復這一步驟,直至所有點加入S為止。

2、算法實現

  dist[n]:dist[i]表示當前找到的從源點v0出發到終點vi的最短路徑的長度,初始化時,dist[i] = edge[v0][i]

  S[n]:S[i]為0表示頂點vi還未加入到集合S中,初始化時S[v0]=1,其余為0

  path[n]:path[i]表示v0到vi的最短路徑上頂點vi的前一個頂點序號。采用“倒向追蹤”方法,確定v0到vi的最短路徑上的每個頂點

  初始化:dist[k] = edge[v0][k]v0是源點S[v0]=1

  遞推:
    u = min{dist[t]}s[vt] = 0;

    u表示當前T集合中dist數組元素值最小的頂點的序號,以後u加入集合S。

    dist[k] = min(dist[k], dist[u] + edge[u][k])S[vk] = 0;

https://blog.csdn.net/qq_35644234/article/details/60870719

3.代碼實現:

輸入:

6 9
0 2 5
0 3 30
1 0 2
1 4 8
2 5 7
2 1 15
4 3 4
5 3 10
5 4 18

輸出:

從0到1距離是:20 0->2->1
從0到2距離是: 5 0->2
從0到3距離是:22 0->2->5->3
從0到4距離是:28 0->2->1->4
從0到5距離是:12 0->2->5

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6
#include<queue> 7 #include<stack> 8 #include<map> 9 #include<sstream> 10 using namespace std; 11 typedef long long ll; 12 const int maxn = 1e3 + 10; 13 const int INF = 1 << 30; 14 int T, n, m; 15 int Map[maxn][maxn];//鄰接矩陣存圖 16 int v[maxn];//v[i] = 1表示已加入集合S 17 int d[maxn];//dist[i]表示距離源點的最短距離 18 int path[maxn];//記錄路徑 19 void dijkstra(int u0)//求頂點為u到其他頂點的最短路 20 { 21 memset(v, 0, sizeof(v)); 22 for(int i = 0; i < n; i++)d[i] = (i == u0 ? 0 : INF); 23 for(int i = 0; i < n; i++)path[i] = -1; 24 for(int i = 0; i < n; i++)//每次加入一個節點,循環n次 25 { 26 int x, m = INF; 27 for(int y = 0; y < n; y++)if(!v[y] && d[y] <= m)m = d[x = y];//記錄當前最小值 28 v[x] = 1;//標記已經加入集合 29 for(int y = 0; y < n; y++) 30 { 31 if(d[y] > d[x] + Map[x][y])//松弛操作 32 { 33 d[y] = d[x] + Map[x][y]; 34 path[y] = x; 35 } 36 } 37 } 38 for(int i = 0; i < n; i++) 39 { 40 if(i == u0)continue; 41 printf("從%d到%d距離是:%2d ", u0, i, d[i]); 42 stack<int>q; 43 int x = i; 44 while(path[x] != -1) 45 { 46 q.push(x); 47 x = path[x]; 48 } 49 cout<<u0; 50 while(!q.empty()) 51 { 52 cout<<"->"<<q.top(); 53 q.pop(); 54 } 55 cout<<endl; 56 } 57 } 58 int main() 59 { 60 cin >> n >> m; 61 for(int i = 0; i < n; i++) 62 { 63 for(int j = 0; j < n; j++) 64 { 65 if(i == j)Map[i][j] = 0; 66 else Map[i][j] = INF; 67 } 68 } 69 int x, y, z; 70 for(int i = 0; i < m; i++) 71 { 72 cin >> x >> y >> z; 73 Map[x][y] = z; 74 } 75 dijkstra(0); 76 return 0; 77 }

上述代碼時間復雜度O(n2),這裏可以將求最小值用優先隊列優化,時間復雜度降低到了O(nlog(n)),下面用結構體將其封裝起來

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<sstream>
using namespace std;
typedef long long ll;
const int maxn = 1e3 + 10;
const int INF = 1 << 30;
int T, n, m;
struct edge
{
    int from, to, dist;
    edge(int u, int v, int d):from(u), to(v), dist(d){}
    edge(){}
};
struct Heapnode
{
    int d, u;//d為距離,u為起點
    Heapnode(){}
    Heapnode(int d, int u):d(d), u(u){}
    bool operator <(const Heapnode & a)const
    {
        return d > a.d;//這樣優先隊列先取出d小的
    }
};
struct Dijkstra
{
    int n, m;
    vector<edge>edges;//存邊的信息
    vector<int>G[maxn];//G[i]表示起點為i的邊的序號集
    bool v[maxn];//標記點是否加入集合
    int d[maxn];//起點s到各個點的最短路
    int p[maxn];//倒敘記錄路徑
    Dijkstra(){}
    void init(int n)
    {
        this -> n = n;
        for(int i = 0; i < n; i++)G[i].clear();
        edges.clear();
    }
    void addedge(int from, int to, int dist)
    {
        edges.push_back(edge(from, to, dist));
        m = edges.size();
        G[from].push_back(m - 1);//存以from為起點的下一條邊
    }
    void dijkstra(int s)//以s為起點
    {
        priority_queue<Heapnode>q;
        for(int i = 0; i < n; i++)d[i] = INF;
        d[s] = 0;
        memset(v, 0, sizeof(v));
        memset(p, -1, sizeof(p));
        q.push(Heapnode(0, s));
        while(!q.empty())
        {
            Heapnode now = q.top();
            q.pop();
            int u = now.u;//當前起點
            if(v[u])continue;//如果已經加入集合,continue
            v[u] = 1;
            for(int i = 0; i < G[u].size(); i++)
            {
                edge& e = edges[G[u][i]];//引用節省代碼
                if(d[e.to] > d[u] + e.dist)
                {
                    d[e.to] = d[u] + e.dist;
                    p[e.to] = G[u][i];//記錄e.to前的邊的編號
                    q.push(Heapnode(d[e.to], e.to));
                }
            }
        }
    }
    void output(int u)
    {
        for(int i = 0; i < n; i++)
        {
            if(i == u)continue;
            printf("從%d到%d距離是:%2d   ", u, i, d[i]);
            stack<int>q;//存的是邊的編號
            int x = i;//x就是路徑上所有的點
            while(p[x] != -1)
            {
                q.push(x);
                x = edges[p[x]].from;//x變成這條邊的起點
            }
            cout<<u;
            while(!q.empty())
            {
                cout<<"->"<<q.top();
                q.pop();
            }
            cout<<endl;
        }
    }
};
Dijkstra ans;
int main()
{
    cin >> n >> m;
    ans.init(n);
    for(int i = 0; i < m; i++)
    {
        int u, v, w;
        cin >> u >> v >> w;
        ans.addedge(u, v, w);
    }
    int u = 0;
    ans.dijkstra(u);
    ans.output(u);
}

單源最短路徑---Dijkstra算法