zoukankan      html  css  js  c++  java
  • 单源最短路径---Dijkstra算法

    传送门:

    Dijkstra

    Bellman-Ford

    SPFA

    Floyd

    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前的边的编号,p存的是边的下标,这样可以通过边找出之前的点以及每条路的路径,如果用邻接矩阵存储的话这里可以直接存节点u
                        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);
    }
  • 相关阅读:
    北漂IT男返乡2年的三线楼市观察(宜昌夷陵篇)-原创
    写一本书作者到底能拿到多少稿酬?
    书是如何定价的?
    一本书出版社拿多少,作者拿多少?书的成本几何?出版一本书出版社到底能赚多少钱?(转)
    微服务架构最强详解
    今日头条号短视频自媒体研究---最开始的短视频设备资金投入不要太大(原创)
    今日头条号短视频自媒体研究---新手上路,正确拍短视频并上传(原创)
    HTTP请求中的缓存(cache)机制
    linux kernel 中断子系统之(一)-- ARM GIC 硬件【转】
    嵌入式Linux——kmsg:分析/proc/kmsg文件以及写自己的/proc/mymsg【转】
  • 原文地址:https://www.cnblogs.com/fzl194/p/8728018.html
Copyright © 2011-2022 走看看