• 朴素迪氏最短单源路径的原理及C++实现


    Dijkstra算法,翻译为迪杰斯特拉或狄克斯特拉。在下驽钝,记不住如此长的翻译,故简称迪氏。

    时间复杂度

    O(n2),端点数的平方。

    使用前提

    边的权为正。可以非连通,非连通的距离为-1。

    原理

    源点到源点的最短路径只有一个节点{s}。除源点本身外,其它端点的最短路径至少有两个端点,整个路径{s...x2}可以拆分为两部分Path1={s...x1}和Path2={x2}。x2是最后节点,且Path1就是s到x1的最短路径。假定Path3是s到x1的最短路径,那Path3+Path2比Path1+Path2短,与Path1+Path2是最短路径矛盾。
    按距离源点距离升序排序,第i个端点(i>0)的最短路径倒数第二个点一定取自[0,i)。x1不会等于x2,否则直接丢掉最后的x2。假定x1的最短距离第m大,m>i。那{s...x1}+{x2}显然比s{...x1}大,那么i > m,与m > i矛盾。

    思路

    两层循环,第一层循环依次处理,最短路径第i小的端点的最小路径。
    第二层循环依次完成以下两个职责:
    更新各点通过第i-1小端点到源点的距离。注意:已处理点,无需处理。如果距离变大无需处理。
    求最短距离第i小的点。
    m_vDis记录源点到各点的最短距离。
    m_vPre记录各点最短路径的倒数第二个端点,方便获取最短路径。目的有二:一,增加理解性。二,某些场景会用到。
    两个函数,分别通过邻接表和邻接矩阵获取最短路径。

    核心代码

    1. class CN2Dis
    2. {
    3. public:
    4.     CN2Dis(int iSize) :m_iSize(iSize), DIS(m_vDis), PRE(m_vPre)
    5.     {
    6.     }
    7.     void Cal(int start, const vectorint, int>>>& vNeiB)
    8.     {
    9.         m_vDis.assign(m_iSize, -1);
    10.         m_vPre.assign(m_iSize, -1);
    11.         vector<bool> vDo(m_iSize);//点是否已处理
    12.         auto AddNode = [&](int iNode)
    13.         {
    14.             //const int iPreNode = m_vPre[iNode];
    15.             long long llPreDis = m_vDis[iNode];
    16.             vDo[iNode] = true;
    17.             for (const auto& it : vNeiB[iNode])
    18.             {
    19.                 if (vDo[it.first])
    20.                 {
    21.                     continue;
    22.                 }
    23.                 if ((-1 == m_vDis[it.first]) || (it.second + llPreDis < m_vDis[it.first]))
    24.                 {
    25.                     m_vDis[it.first] = it.second + llPreDis;
    26.                     m_vPre[it.first] = iNode;
    27.                 }
    28.             }
    29.             long long llMinDis = LLONG_MAX;
    30.             int iMinIndex = -1;
    31.             for (int i = 0; i < m_vDis.size(); i++)
    32.             {
    33.                 if (vDo[i])
    34.                 {
    35.                     continue;
    36.                 }
    37.                 if (-1 == m_vDis[i])
    38.                 {
    39.                     continue;
    40.                 }
    41.                 if (m_vDis[i] < llMinDis)
    42.                 {
    43.                     iMinIndex = i;
    44.                     llMinDis = m_vDis[i];
    45.                 }
    46.             }
    47.             return (LLONG_MAX == llMinDis) ? -1 : iMinIndex;
    48.         };
    49.         int next = start;
    50.         m_vDis[start] = 0;
    51.         while (-1 != (next = AddNode(next)));
    52.     }
    53.     void Cal(int start, const vectorint>>& mat)
    54.     {
    55.         m_vDis.assign(m_iSize, LLONG_MAX);
    56.         m_vPre.assign(m_iSize, -1);
    57.         vector<bool> vDo(m_iSize);//点是否已处理
    58.         auto AddNode = [&](int iNode)
    59.         {
    60.             long long llPreDis = m_vDis[iNode];
    61.             vDo[iNode] = true;
    62.             for (int i = 0; i < m_iSize; i++)
    63.             {
    64.                 if (vDo[i])
    65.                 {
    66.                     continue;
    67.                 }
    68.                 const long long llCurDis = mat[iNode][i];
    69.                 if (llCurDis <= 0)
    70.                 {
    71.                     continue;
    72.                 }
    73.                 m_vDis[i] = min(m_vDis[i], m_vDis[iNode] + llCurDis);
    74.             }
    75.             long long llMinDis = LLONG_MAX;
    76.             int iMinIndex = -1;
    77.             for (int i = 0; i < m_iSize; i++)
    78.             {
    79.                 if (vDo[i])
    80.                 {
    81.                     continue;
    82.                 }
    83.                 if (m_vDis[i] < llMinDis)
    84.                 {
    85.                     iMinIndex = i;
    86.                     llMinDis = m_vDis[i];
    87.                 }
    88.             }
    89.             if (LLONG_MAX == llMinDis)
    90.             {
    91.                 return -1;
    92.             }
    93.             m_vPre[iMinIndex] = iNode;
    94.             return iMinIndex;
    95.         };
    96.         int next = start;
    97.         m_vDis[start] = 0;
    98.         while (-1 != (next = AddNode(next)));
    99.     }
    100.     const vector<long long>& DIS;
    101.     const vector<int>& PRE;
    102. private:
    103.     const int m_iSize;
    104.     vector<long long> m_vDis;//各点到起点的最短距离
    105.     vector<int>  m_vPre;//最短路径的前一点
    106. };

    测试用例

    #include
    #include
    #include
    #include
    using namespace std;

    class CDebugN2Dis : public CN2Dis
    {
    public:
        using CN2Dis::CN2Dis;
        void Assert(const vector& vDis)
        {
            for (int i = 0; i < vDis.size(); i++)
            {
                assert(vDis[i] == DIS[i]);
            }
        }
    };

    struct CDebugParam
    {
        int n;
        vector>> edges;
        int s;
        vector dis;//答案
    };

    int main()
    {
        vector params = { {1,{{}},0,{0}},
            {2,{{}},0,{0,-1}},{2,{{{1,2}},{{0,2}}},0,{0,2} }
            ,{3,{{{1,4},{2,5}},{{0,4}},{{0,5}}},0,{0,4,5} }
            ,{3,{{{1,4},{2,8}},{{0,4},{2,3}},{{0,8},{1,3}}},0,{0,4,7} }
            ,{3,{{{1,4},{2,8}},{{0,4},{2,5}},{{0,8},{1,5}}},0,{0,4,8} }
        };
        for (const auto& par : params)
        {
            CDebugN2Dis n2Dis(par.n);
            n2Dis.Cal(par.s, par.edges);
            n2Dis.Assert(par.dis);
        }
    }

    测试环境

    win10  VS2022  C++17

    相关下载

    源码及测试样例下载:

    朴素迪氏最短单源路径的原理及C++源码及测试用例

    【免费】朴素迪氏最短单源路径的原理及C++源码及测试用例资源-CSDN文库

    https://img-blog.csdnimg.cn/ea2601b3918f4aef836b5fe30da2ebf7.gif#pic_center#pic_center

    其它

    视频课程

    如果你觉得复杂,想从简单的算法开始,可以学习我的视频课程。

    https://edu.csdn.net/course/detail/38771

    我的其它课程

    https://edu.csdn.net/lecturer/6176

    测试环境

    win7 VS2019 C++17 或Win10 VS2022 Ck++17

    相关下载

    算法精讲《闻缺陷则喜算法册》doc版

    https://download.csdn.net/download/he_zhidan/88348653

    作者人生格言

    有所得,以墨记之,故曰墨家

    闻缺陷则喜。问题发现得越早,越给老板省钱。

    算法是程序的灵魂

    https://img-blog.csdnimg.cn/f95ddae62a4e43a68295601c723f92fb.gif#pic_center

  • 相关阅读:
    ClickHouse的 MaterializeMySQL引擎
    尾矿库监测 GNSS北斗高精度定位终端机应用
    github上创建分支并合并到master
    【Java基础】方法
    不渴望得到,不害怕失去|佛系态度|无所谓,无欲无求 状态分析
    人工智能轨道交通行业周刊-第59期(2023.9.4-9.10)
    傻白入门芯片设计,一颗芯片的诞生(九)
    【Python】Python基础
    力扣-排序算法
    网络安全测试中内网横向拓展的途径
  • 原文地址:https://blog.csdn.net/he_zhidan/article/details/133442182