优先算法专题十六——BFS解决最短路径问题

倒水问题与BFS:从隐式图搜索到最短路径的算法实战 在算法竞赛中,隐式图搜索是一类将现实操作抽象为状态节点与转移边的问题求解框架。其核心原理是利用广度优先搜索(BFS)在无权图中逐层扩展,从而保证首次到达目标状态时即为最短路径,并配合状态压缩优化存储与去重效率。这一技术价值突出,常用于倒水问题、迷宫寻路、八数码拼图等经典场景,是解决“最少步骤”类题目的通用钥匙。以蓝桥杯省赛常考的倒水问题为例,文章从状态表示、倒水操作枚举、BFS剪枝到代码实现逐步拆解,并补充了贝祖定理数学判定与常见坑点,帮助读者建立完整的算法思维。无论你是备战竞赛还是提升算法基本功,掌握状态 阅读详情

概述:最短路径问题就是边权为一的路径问题,每一次往外走一步步数加上边权,走到目的地步数最少的就是最短路。这种问题一般需要层次遍历来进行辅助,因为层次遍历可以找出本层连接的下一层的地点;一般还要有个哈希表记录地点访问过没有,防止走重复的路。 

 1926. 迷宫中离入口最近的出口 - 力扣(LeetCode)

每次向外扩展一层,扩展之前提前让总步数加一(下一次向外扩展),若是在下一次扩展中找到了出口就直接返回

class Solution {
public:
    vector<int> dx = {0, 0, -1, 1};
    vector<int> dy = {-1, 1, 0, 0};
    vector<vector<bool>> vis{100, vector<bool>(100, false)};

    int nearestExit(vector<vector<char>>& maze, vector<int>& entrance) {
        int n = maze.size(), m = maze[0].size();
        int ans = 0;
        queue<pair<int, int>> myq;

        myq.push({entrance[0], entrance[1]});
        vis[entrance[0]][entrance[1]] = true;
        while(myq.size())
        {
            ans++;
            //开始向外扩展一层
            int size = myq.size();
            for(int i = 0; i < size; i++)
            {
                auto [a, b] = myq.front();
                myq.pop();
                for(int k = 0; k < 4; k++)
                {
                    int x = a + dx[k], y = b + dy[k];
                    if(x >= 0 && x < n && y >= 0 && y < m && !vis[x][y] && maze[x][y] == '.')
                    {
                        if(x == 0 || x == n - 1 || y == 0 || y == m - 1) return ans;

                        myq.push({x, y});
                        vis[x][y] = true;
                    }
                }
            }
        }
        return -1;
    }
};

433. 最小基因变化 - 力扣(LeetCode)

新增用法:在unordered_map和unordered_set中取一个用,若是不需要映射值就用unordered_set

思路:

    //将问题转换为BFS解决最短路径问题
    //由最开始的基因序列一层层扩展查找,每一次扩展的内容为这个基因序列变化的所有可能
    //由一个队列记录某一次扩展的基因序列
    //只有之前没有被扩展(若是之前已经扩展过再加入队列,那么就重复扩展了,这条路上一定不是最小的次数)的并且在bank里面的才会入队列

class Solution {
public:

    int minMutation(string startGene, string endGene, vector<string>& bank) 
    {
        int ans = 0;//最终结果

        unordered_set<string> hash_bank(bank.begin(), bank.end()), hash_search;//方便查看某个序列在不在bank内、查看某个序列是否被遍历过
            
        if(startGene == endGene) return ans;
        if(hash_bank.find(endGene) == hash_bank.end()) return -1;//最终结果本身不在

        queue<string> myq;
        myq.push(startGene);
        hash_search.insert(startGene);

        char genes[4] = {'A', 'G', 'C', 'T'};
        while(myq.size())
        {
            ans++;//准备开始下一次扩展
            int size = myq.size();
            while(size--)//将上一次的序列全部扩展完
            {
                string str = myq.front();//将此序列变化,扩展
                myq.pop();
                for(int i = 0; i < str.size(); i++)
                {
                    char origin = str[i];
                    for(auto& gene : genes)
                    {
                        if(gene == origin)
                            continue;//跳过原来的字符串
                        string next = str;
                        next[i] = gene;//扩展字符串

                        //先判断是不是结果字符串,因为之前判断了endGene在不在bank中,走到这一定是在。那么只需要判断next和endGene相同与否即可
                        if(endGene == next) return ans;

                        //不是并且没有被访问过并且在bank中就入队列
                        if(hash_bank.find(next) != hash_bank.end() && hash_search.find(next) == hash_search.end())
                        {
                            myq.push(next);
                            hash_search.insert(next);
                        }
                    }
                }
            }
        }
        return -1;
    }
};

127. 单词接龙 - 力扣(LeetCode)

和上题类似

class Solution {
public:
    int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
        if(beginWord == endWord) return 1;//相同直接返回0
        unordered_set<string> hash_list(wordList.begin(), wordList.end());//简化在wordlist里面查找存不存在的过程
        if(hash_list.count(endWord) == 0) return 0;//endWord不存在直接返回0

        unordered_set<string> hash_search;//标记访问过
        hash_search.insert(beginWord);

        queue<string> myq;//层次遍历
        myq.push(beginWord);

        int ans = 1;
        vector<char> words(26, 0);
        for(int i = 0; i < 26; i++)
            words[i] = 'a' + i;
        while(myq.size())
        {
            ans++;
            int size = myq.size();
            while(size--)//一次扩展
            {
                string cur = myq.front();
                myq.pop();
                for(int i = 0; i < cur.size(); i++)
                {
                    char origin = cur[i];
                    for(auto& ch : words)
                    {
                        if(ch == origin) continue;

                        string next = cur; next[i] = ch;
                        if(next == endWord) return ans;
                        //在hash_list里面并且未被访问就进队列并且标记已访问过
                        if(hash_list.count(next) && !hash_search.count(next))
                        {
                            myq.push(next);
                            hash_search.insert(next);
                        }
                    }
                }
            }
        }
        return 0;
    }
};

675. 为高尔夫比赛砍树 - 力扣(LeetCode)

因为题意是按照树的高度进行砍树,所以要找出下一次砍树的坐标,需要先将树的坐标按照树的高度排序;

之后将下棵树的下标作为迷宫问题的终点,起点为上一次的终点开始进行bfs查找

class Solution {
public:
//将这个问题分解为多步的迷宫问题,每次的出口换成了下一次应该砍的树的下标,依次统计步数即可
typedef pair<int, int> PII;
int n, m;
    int cutOffTree(vector<vector<int>>& forest) 
    {
        n = forest.size();
        m = forest[0].size();
        //首先将砍的树的下标按照树的高度排序
        vector<PII> sortindex;
        for(int i = 0; i < n; i++)
            for(int j = 0; j < m; j++)
                if(forest[i][j] > 1) sortindex.push_back({i, j});
        sort(sortindex.begin(), sortindex.end(), [&](const PII& xy1, const PII xy2)->bool{
            return forest[xy1.first][xy1.second] < forest[xy2.first][xy2.second];
        });//[&]捕捉forest里面的数

        //多次进行统计寻找下一颗树所需步数的操作
        int ans = 0;
        int bx = 0, by = 0;//起点
        for(auto& [a, b] : sortindex)
        {
            int ret = bfs(forest, bx, by, a, b);
            if(ret == -1) return -1;//说明下一棵树的位置到不了
            ans += ret;
            //下一次寻找的起点为上一次寻找的终点
            bx = a;
            by = b;
        }
        return ans;
    }
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
bool vis[51][51] = {false};//避免重复回走
    int bfs(vector<vector<int>>& forest, int bx, int by, int ex, int ey)
    {
        if(bx == ex && by == ey) return 0;

        memset(vis, false, sizeof vis);//每一次都是新的查找,所以要重新标记
        int ret = 0;
        queue<PII> q;
        q.push({bx, by});
        vis[bx][by] = true;

        while(q.size())
        {
            ret++;
            int sz = q.size();
            while(sz--)
            {
                auto [a, b] = q.front();
                q.pop();
                for(int i = 0; i < 4; i++)
                {
                    int x = a + dx[i], y = b+ dy[i];

                    if(x == ex && y == ey) return ret;

                    if(x >= 0 && x < n && y >= 0 && y < m && !vis[x][y] && forest[x][y] != 0)
                    {
                        q.push({x, y});
                        vis[x][y] = true;
                    }
                }
            }
        }
        return  -1;
    }
};

知识点十六:深度/广度优先搜索 前言 在社交网络中,有一个六度分割理论,具体是说,你与世界上的另一个人间隔的关系不会超过六度,也就是说平均只需要六步就可以联系到任何两个互不相识的人。 一个用户的一度连接用户很好理解,就是他的好友,二度连接用户就是他好友的好友,三度连接用户就是他好友的好友的好友。在社交网络中,我们往往通过用户之间的连接关系,来实现推荐“可能认识的人”这么一个功能。今天的开篇问题就是:给你一个用户,如何找出这个用户... 阅读详情

相关推荐

十六进制网格中的广度优先搜索项目实践

本文还有配套的精品资源,点击获取 简介:本项目聚焦于在十六进制网格上实现广度优先搜索(BFS)算法,一个基础但关键的数据结构与算法问题。十六进制网格提供了一种类似于现实世界中空间布局的方式,它不同于传统的方形网格。项目将详细介绍如何在这样的网格上应用BFS算法,并且会涉及到节点类的定义、队列的使用以及坐标系统的操作。通过项目的实践,学习者将加深对数据结构和算法的理解,特别是...

weixin_32661831的博客 757

力扣打卡day7--bfs常见题目类型一(最短路径类)

现在有 n 个传送门,你处在第一个传送门的位置,第 i 个传送门可以将你传送到第 i-a[i] 到第 i+a[i] 范围内的任意一个传送门,请问你最少需要几次操作,使得你可以传送到最后一个传送门的位置。具体的,当小明在x的位置使用传送法术,会被传送到n-x-1的位置。例如,当n=5时,如果小明在0位置使用传送法术,会被传送到4的位置。移动或使用法术都需要一步,现在小明想知道,最少几步它可以从起点走到迷宫的出口?此外,小明还有一个可以无限使用的传送法术,使用后会被传送到镜像的位置。如果无法到达,输出-1。

weng16的博客 589

leetcode走迷宫-leetcodeGo:leetcode刷题

leetcode 走迷宫 leetcode 刷题记录 类型要点 链表 链表相关操作: 翻转 区间翻转 判断环 ---- 快慢指针 对称翻转 链表常用技巧 递归 定义双变量 let head = p = {}; p.next = l1 这类定义法则 广度遍历 要点: 需要一个队列 queue 每一层遍历时,将当前长度取出来,确保遍历本层节点 循环 长度 次,每次 shift() 一个节点 把下层节点 posh() 到队列中 案例: 树的层序遍历 走迷宫 寻找最短路径 总结注意点: 递归时,需要注意结束条件 每日一题 20.3.29 --- 20.3.28 --- 20.3.30 --- 20.3.31 ---

LeetCode 505. 迷宫 II(BFS / Dijkstra 最短路径)

文章目录1. 题目2. 解题2.1 BFS2.2 Dijkstra 最短路径 1. 题目 由空地和墙组成的迷宫中有一个球。 球可以向上下左右四个方向滚动,但在遇到墙壁前不会停止滚动。 当球停下时,可以选择下一个方向。 给定球的起始位置,目的地和迷宫,找出让球停在目的地的最短距离。 距离的定义是球从起始位置(不包括)到目的地(包括)经过的空地个数。 如果球无法停在目的地,返回 -1。 迷宫由一个0和1的二维数组表示。 1表示墙壁,0表示空地。 你可以假定迷宫的边缘都是墙壁。 起始位置和目的地的坐标通过行号和列

Michael是个半路程序员 5826

迷宫最短路径算法(dfs)

这是一个求迷宫最短路径的算法,用的是dfs的思想~~~~~~~~~~~~~

Windows游戏多开检测实战:5种技术原理与破解方法详解(附C++代码)

本文深入解析了Windows游戏多开检测的5种核心技术原理,包括进程枚举、互斥体、信号量、窗口及文件映射检测,并详细探讨了对应的破解方法。通过分析这些基于进程和内核对象的攻防机制,为开发者与逆向爱好者提供了从底层理解Windows系统进程管理的实战视角,并附有核心C++代码示例。

weixin_29315091的博客 243

Leetcode迷宫问题 BFS 整体思路及实现

来自小白上了算法课之后觉得自己的coding能力是在太差了,记录一下大佬的leetcode499迷宫问题的解答,加上了自己的注释和理解。还有结构图。 leetcode三道题都是BFS的延伸问题进行一些改动, 下面是一些区别的点: 1.490结果给出是否能到达即可,目的地是星(即停到此处才可以) 2.505结果给出能到达的最短路径即可,结果输出可以或者不可以,目的地是星(即停到此处才可以) 3.499结果是给出最短路径并进行字符串比较(输出包括上下左右的方向的字符串),目的地是洞(即路径中遇到过该点即可)(这

weixin_45719088的博客 2941

Python实战:动态爬取国家地表水水质实时监测数据(附最新代码解析)

本文详细介绍了使用Python动态爬取国家地表水水质实时监测数据的实战方法。针对动态网站数据加载特点,重点解析了如何利用Selenium模拟浏览器操作、结合BeautifulSoup解析数据,并提供了最新的代码实现与常见问题解决方案,帮助开发者高效获取环境监测数据。

app77的博客 280

【专题十六】BFS 解决最短路径

【专题十六】BFS 解决最短路径:1926. 迷宫中离入口最近的出口、433. 最小基因变化、127. 单词接龙、675. 为高尔夫比赛砍树

tan_run的博客 787

卡尔曼滤波调参避坑指南:Q/R参数怎么设?实测5种传感器场景

本文针对卡尔曼滤波在工程实践中Q/R参数设置的难题,提供了一套实用的调参避坑指南。通过分析过程噪声方差Q与测量噪声方差R的物理意义与博弈关系,并结合温度传感器、陀螺仪、超声波测距等五种典型传感器场景的实测效果对比,总结出从噪声估算、离线仿真到收敛测试的系统性调参方法论,帮助工程师快速实现稳定有效的滤波效果。

weixin_29174141的博客 804

VS Code 配置 LaTeX 写作环境完全指南

本文详细介绍了如何在 VS Code 中配置 LaTeX 写作环境,涵盖了从安装必备组件到高级功能的全面指南。首先,用户需要安装 LaTeX 发行版(如 TeX Live 或 MiKTeX)和 VS Code 插件(如 LaTeX Workshop)。接着,通过修改 settings.json 和 keybindings.json 文件,用户可以自定义编译、查看快捷键等基础配置。文章还提供了高效写作技巧,如使用代码片段和多文件项目管理,并介绍了高级功能如反向同步、公式预览和参考文献管理。此外,针对常见问题(

weixin_70043030的博客 1984

【优选算法】专题十六——BFS解决最短路径问题

复习解题思路和代码实现及解析复习解题思路本题与上一题同为最短路径问题,在代码实现中看看这种实际问题转化为最短路径问题之后是怎么与BFS算法结合的、细节是怎么处理的(尤其注意基因变化那一步)

2502_91380778的博客 660

VirtualBox虚拟机上ubuntu系统安装问题记:显示画面太小、启动就异常退出等

报错:Failed to load R0 module D:/VMMR0.r0: The path is not clean of leading double slashes: ‘D:/VMMR0.r0’ (VERR_SUPLIB_PATH_NOT_CLEAN).解决方法特别简单,就是安装VIrtualBox的时候不要安装在CDE等盘根目录下。首先VirtualBox的下载安装过程是比较简单的,此处就不赘述了。然后E盘下新建个目录,安装到这个目录下就可解决。

qq_42595610的博客 2826

【每日算法】专题十六_BFS 解决最短路问题

本文探讨了BFS(广度优先搜索)算法在解决最短路问题中的应用,重点分析了其在无权图或边权为1的图中的高效性。BFS通过分层遍历和队列管理,保证首次访问目标节点时即得到最短路径。文章通过四个LeetCode例题(迷宫最近出口、最小基因变化、单词接龙、高尔夫砍树)详细阐释了BFS的实现细节:1)使用队列控制访问顺序;2)维护visited标记避免重复;3)分层扩展时步数统计;4)针对不同问题的特殊处理(如边界检查、变异生成等)。每个例题都包含问题分析、算法设计、复杂度评估和实现代码,展示了BFS在空间和时间复杂

weixin_58252863的博客 1219

WEB浏览器视频流播放方案

基于Media Source Extensions播放视频流 浏览器播放视频的几种方法 一、H5 video标签 在浏览器播放视频,可以使用HTML5原生的video标签。但其播放的格式使用一定限制的,目前video只支持三种格式WebM、Ogg、MP4。 WebM:WebM 文件使用 VP8 视频编解码器和 Vorbis 音频编解码器 Ogg :Ogg 文件使用 Theora 视频编解码器和 Vorbis音频编解码器 MP4: MPEG 4文件使用 H264 视频编解码器和AAC音频编解码器 上面三种

machh的专栏 2381

2026最新版OpenClaw安装:Windows WSL2从零到跑通

Windows WSL2安装OpenClaw指南 本文详细介绍了在Windows系统上通过WSL2部署OpenClaw AI助理的完整流程。WSL2结合了Windows易用性和Linux高性能,特别适合Windows用户、开发者、学生和技术爱好者。文章涵盖硬件要求(推荐i5/16GB/SSD)、系统准备(Windows 10/11+WSL2)、环境部署(Python/Node.js/Redis)和OpenClaw配置(克隆/编译/初始化)等关键步骤。通过WSL2,用户可在保留Windows操作习惯的同

一键难忘的博客 2345

【优选算法专栏】专题十六:BFS解决最短路问题(一)

BFS解决最短路问题(一)

小小unicorn的博客 673

【AI大模型应用开发】【LangChain系列】实战案例6:利用大模型进行文本总结的方法探索,文本Token超限怎么办?

假设有一组文档(PDF、Notion页面、客户问题等),你想要总结内容。可以利用大模型来帮你。今天来系统看下利用大模型来对文本进行总结的方法,以LangChain的使用为例。

同学小张的博客 3749

算法专题十六:BFS

【代码】算法专题十六:BFS。

blamep的博客 413

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

广度优先算法专题---例题讲解+总结+技巧

个人的理解:广度优先搜索属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。假如是在二维数组里面搜索,就是一变四,四遍十六等。 具体看一个BFS特别经典的例题: 题目连接:https://nanti.jisuanke.com/t/T1596 题目描述 蒜头君在你的帮助下终于逃出了迷宫,但是蒜头君并没...

好好学习。天天编程 942

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

算法笔记(十三)——BFS 解决最短路问题

是解决最短路径问题的一种常见算法。在这种情况下,我们通常使用BFS来查找从一个起始点到目标点的最短路径。

m0_74317866的博客 912

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

c++ 遍历所有点且距离最短_最短路径问题求解

最近对“最短路径问题”产生了兴趣,没有买到回家的票,于是趁着这个假期,好好研究了一番。经过一通学习外加尝试,于是通过Python实现了演示效果。代码已经放到了Github账号上,供参考。当然,目前只是初期版本,后期有时间还会更新,所以如果有感兴趣的可以关注,如果有什么改进建议欢迎发起Pull Request。先简单描述一下最短路径问题:旅行商问题,其实讲的是一个旅行商,到了一个陌生的地方,手中只有...

weixin_42107561的博客 3748

图论专题(二十六):最短路径的“黄金法则”——Dijkstra 攻克「网络延迟时间」

今天,我们掌握了图论中最重要的算法之一。你可以把Dijkstra看作是BFS 的“带权升级版”BFS使用普通队列,每次弹出“层数”最小的。Dijkstra使用优先队列,每次弹出“实际距离”最小的。这个模板是解决所有“非负权图单源最短路径”问题的标准答案。在下一篇中,我们将挑战 Dijkstra 的一个有趣变种。如果“路径的距离”不是指“边权之和”,而是指“路径上最大的那条边的权重”(瓶颈路径),Dijkstra 还能用吗?答案是肯定的,而且非常优雅。下期见!

2301_80334067的博客 1047

算法奇妙屋(十六)-BFS解决边权为1的多源最短路径问题

【代码】算法奇妙屋(十六)-边权为1的多源最短路径问题。

景画的博客 344

步步为营(十六)搜索(二)BFS 广度优先搜索

上一篇讲了DFS,那么与之对应的就是BFS,也就是 宽度优先遍历,又称广度优先搜索算法。首先,让我们回忆一下什么是“深度”: 更学术点的说法,可以看做“单位距离下,离起始状态的长度” 那么广度是什么呢? 个人觉得,可以这么归纳: 何为广度? 可以看做“距离初始状态距离相等的结点”的集合 那么BFS的核心思想就是:从初始结点开始,搜索生成第一层结点,检查目标结点是否在这些结点中,若没有,再将

Kernight 955

无人驾驶汽车系统入门(十六)——最短路径搜索之A*算法

无人驾驶汽车系统入门(十六)——最短路径搜索之A*算法 路线规划中一个很核心的问题即最短路径的搜索,说到最短路径的搜索我们就不得不提A*算法,虽然原始的A*算法属于离散路径搜索算法(我们的世界是连续的),但是其使用启发式搜索函数的理念却影响着我们后面会介绍的连续路径搜索算法,所以在介绍连续路径搜索算法之前,理解基本的A*算法是很有必要的,本节我们从广度优先算法出发,一步步改良算法直到引出A...

AdamShan的博客 1万+
上一篇: 优先算法专题十五——BFS_FloodFill
下一篇: 优先算法专题十七——多源BFS
溪苏.
博客等级 码龄3年 995粉丝 138原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值