• 01BFS最短距离的原理和C++实现


    时间复杂度

    O(n),n是边数。

    使用前提

    边的权只有两种:0,1。

    典型场景

    n个端点的无向图,编号范围[0,n)。Edges0表示{{n1,n2},...{n3,n4}}表示n1和n2,n3和n4之间有路联接。Edges1表示{{n1,n2},...{n3,n4}}表示n1和n2,n3和n4之间有损坏的路连接。要想让s和d之间至少有一条通道,最小需要维修多少条路。如果无法到达,请返回-1。可能有环,但无自环,重边,可能不联通。

    解题思路

    可以用类似上章的思路,没损害的路加到pre中,损坏的路加到que中。距离相等的点,谁先谁后无所谓。需要维修的路入队的时候不能计算最短距离,因为不一定是最短边。改在入队计算最短距离,第一层循环记录最短距离。

    核心代码

    1. class CBFS1
    2. {
    3. public:
    4.     CBFS1(vectorint>>& vNeiB0, vectorint>>& vNeiB1, int s)
    5.     {
    6.         m_vDis.assign(vNeiB0.size(), -1);
    7.         //m_vDis[s] = 0;
    8.         queue<int> pre;
    9.         pre.emplace(s);
    10.         for (int i = 0; pre.size(); i++)
    11.         {
    12.             queue<int> dp;
    13.             while (pre.size())
    14.             {
    15.                 const int cur = pre.front();
    16.                 pre.pop();
    17.                 if (-1 != m_vDis[cur])
    18.                 {
    19.                     continue;
    20.                 }
    21.                 m_vDis[cur] = i;
    22.                 for (const auto next : vNeiB0[cur])
    23.                 {
    24.                     pre.emplace(next);
    25.                 }
    26.                 for (const auto next : vNeiB1[cur])
    27.                 {
    28.                     dp.emplace(next);
    29.                 }
    30.             }
    31.             dp.swap(pre);
    32.         }
    33.     }
    34. public:
    35.     vector<int> m_vDis;
    36. };

    测试样例

    #define CBFS CBFS1 
    class CDebugBFS : public CBFS
    {
    public:
        using CBFS::CBFS;
        void Assert(const vector& vDis)
        {
            for (int i = 0; i < vDis.size(); i++)
            {
                assert(vDis[i] == m_vDis[i]);
            }
        }
    };

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

    int main()
    {
        vector params = { {1,{},{},0,{0}},{2,{},{},0,{0,-1}},{2,{{0,1}},{},0,{0,0}},{2,{},{{0,1}},0,{0,1}},
        {6,{}, { {0,1},{1,2},{1,3},{2,4},{4,5},{3,5}},0,{0,1,2,2,3,3} },
        {6,{{3,5}}, { {0,1},{1,2},{1,3},{2,4},{4,5}},0,{0,1,2,2,3,2} }
        };
        for (const auto& par : params)
        {
            auto vNeiB0 = EdgeToNeiBo(par.n, par.edges0);
            auto vNeiB1 = EdgeToNeiBo(par.n, par.edges1);
            CDebugBFS bfs(vNeiB0, vNeiB1,par.s);
            bfs.Assert(par.dis);
        }
    }


    类似场景

    魔塔经典问题,砸墙需要一个锄头,没墙的地方可以随便移动,如果用尽可能少的锄头到达目的地。许多游戏经过箭塔附件时,会遭到箭塔攻击。如何已最小的损坏通过箭塔。


    用双向队列优化

    当前状态

    操作

    新状态

    处理结束

    首尾入队

    一种最短距离

    一种最短距离

    出队

    状态不变或变为空

    队首入队

    一种最短距离或两种最短距离

    队尾入队

    一种最短距离或两种最短距离

    二种最短距离

    出队

    状态不变或变为一种最短距离

    队首入队

    两种最短距

    队尾入队

    两种最短距

    1. class C01BFSDis
    2. {
    3. public:
    4.     C01BFSDis(vectorint>>& vNeiB0, vectorint>>& vNeiB1, int s)
    5.     {
    6.         m_vDis.assign(vNeiB0.size(), -1);
    7.         std::dequeint,int>> que;
    8.         que.emplace_back(s,0);
    9.         while (que.size())
    10.         {
    11.             auto it = que.front();
    12.             const int cur = it.first;
    13.             const int dis = it.second;
    14.             que.pop_front();
    15.             if (-1 != m_vDis[cur])
    16.             {
    17.                 continue;
    18.             }
    19.             m_vDis[cur] = it.second;
    20.             for (const auto next : vNeiB0[cur])
    21.             {
    22.                 if (-1 != m_vDis[next])
    23.                 {
    24.                     continue;
    25.                 } 
    26.                 que.emplace_front(next,dis);
    27.             }
    28.             for (const auto next : vNeiB1[cur])
    29.             {
    30.                 if (-1 != m_vDis[next])
    31.                 {
    32.                     continue;
    33.                 }
    34.                 que.emplace_back(next, dis+1);
    35.             }
    36.         }
    37.     }
    38. public:
    39.     vector<int> m_vDis;
    40. };

    下载


    源码下载:
    https://download.csdn.net/download/he_zhidan/88383828

    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

  • 相关阅读:
    MHA高可用配置及故障切换
    R语言编写用户自定义函数:R语言编写用户自定义函数计算多个输入参数的最大公约数(两个输入为数值)
    【2023考研】数据结构常考应用典型例题(含真题)
    Redis 内存优化神技,小内存保存大数据
    运动App如何实现端侧后台保活,让运动记录更完整?
    帕累托分析中的累计优化
    【微服务】Feign远程调用和异步调用请求头丢失问题
    在EF Core中为数据表按列加密存储
    144. 二叉树的前序遍历-C语言
    【Java代码规范】阿里编码规约 VS CheckStyle
  • 原文地址:https://blog.csdn.net/he_zhidan/article/details/133409433