BFS 解决边权为1的最短路问题

news2024/9/20 8:42:49

边权为1的最短路问题

最短路问题:

比如说从D->K,找出最短的那条,其中每条路都是有权值,此篇主要讲解的边权为1的最短路问题

即边权都是一样的。

image-20240917202123546

解法就是从起点开始,做一次BFS:

  • 需要一个队列、一个哈希表(检测是否访问过)
  • 起点进入队列,然后哈希表标记
  • 弹出队头元素,将队头元素能去的位置,加入队列
  • 然后将该层依次元素弹出,弹出时继续加入能去的位置(哈希表检测一下)
  • 到终点就停止

BFS为什么能找出最短路径:

简单理解一下,假设有4条路,相当于4个人一起出发,每个人每次都向后移动一个单位(因为权值为1),最先到的那一个,就直接“跳出循环”了。

image-20240917203151230

如何找出最短路径:

拓展的层数,就是最短路的长度

1926. 迷宫中离入口最近的出口

题目链接:1926. 迷宫中离入口最近的出口

题目解析

题目给了我们两个数组:

  • 二维数组表示迷宫,+表示墙(不能走),.表示空格(可以走)
  • 一维数组:当前起始位置

每次只能往上下左右走一步,遇见墙不能走,让我们求最少走多少步,能走到迷宫(走到就行,不用走出去,没有出口就返回-1)。

矩阵大小为m*n

出口是矩阵的边界位置:x == 0 || x == m -1 || y == 0 || y == n -1

算法原理

每次走一步,找到最少步数,即可以理解为边权为1的最短路问题

  • 每次只能往上下左右走一步
  • 遇墙不走,第一次到边界就直接返回

代码实现

class Solution {
public:
    int dx[4] = {1, -1, 0, 0};
    int dy[4] = {0, 0, 1, -1};
    bool vis[101][101];
    int m = 0;
    int n = 0;
    int nearestExit(vector<vector<char>>& maze, vector<int>& entrance)
    {
        int ret = 0;
        m = maze.size();
        n = maze[0].size();

        //memset(vis, 0, sizeof(vis));

        queue<pair<int, int>> q;
        q.push({entrance[0], entrance[1]});
        vis[entrance[0]][entrance[1]] = true;

        while(q.size())
        {
            ret++;
            int sz = q.size();
            for(int i = 0; i < sz; i++)
            {
                auto [x, y] = q.front();
                q.pop();
                for(int k = 0; k < 4; k++)
                {
                    int a = dx[k] + x;
                    int b = dy[k] + y;
                    if(a >= 0 && a < m && b >= 0 && b < n && maze[a][b] == '.' && !vis[a][b])
                    {
                        if(a == 0 || a == m -1 || b == 0 || b == n -1)
                        {
                            return ret;
                        }
                        q.push({a, b});
                        vis[a][b] = true;
                    }
                }
            }
        }
        return -1;
    }
};

433. 最小基因变化

题目链接:433. 最小基因变化

题目解析

给我们2个基于序列(字符串)startend,再给我们一个基因库序列(vector<string>bank,它们都是由8个字符组成,每个字符都是ACGT其中之一

要我们找出从start 变为 end的最短次数,且每次变化,必须要在基因库能找到对应的。

算法原理

每次只能改变基于序列的一个字符,相当于中间可能会产生很多基因序列,然后才到目标序列。

将起始基于序列抽象成一个点,中间的序列抽象成路径,目标序列也是一个点,这样即转换成了求边权为1的最短路径问题

注意事项:

  • 用哈希表标记搜索过的字符串
  • 对元素字符串一位一位遍历,修改成ACGT其中一个,这样即可枚举出所以变化情况
  • 枚举出的字符串,符合基因库且为搜索过,加入队列
  • 基因库的字符串也丢入哈希表,即可快速判断

代码实现

class Solution {
public:

    int minMutation(string startGene, string endGene, vector<string>& bank)
    {
        string s = "ACGT";
        unordered_set<string> hash(bank.begin(), bank.end());   //基因库
        unordered_set<string> vis;  //是否搜索过

        if(!hash.count(endGene))
        {
            return -1;
        }
        if(startGene == endGene)
        {
            return 0;
        }

        queue<string> q;
        q.emplace(startGene);
        vis.emplace(startGene);
        int ret = 0;
        while(q.size())
        {
            ret++;
            int sz = q.size();
            while(sz--)
            {
                string t = q.front();
                q.pop();
                for(int i = 0; i < 8; i++)
                {
                    string tmp = t; 
                    for(int j = 0; j < 4; j++)
                    {
                        tmp[i] = s[j];
                        if(hash.count(tmp) && !vis.count(tmp))
                        {
                            if(tmp == endGene)
                            {
                                return ret;
                            }
                            q.emplace(tmp);
                            vis.emplace(tmp);
                        }
                    }
                }
            }
        }
        return -1;
    }
};

127. 单词接龙

题目链接:127. 单词接龙

题目解析

这题意思和上面一题类似,就不多说了

唯一不一样的是,返回值为变化的单词数量

算法原理

思路也是和上一题一样

代码实现

class Solution {
public:
    int ladderLength(string beginWord, string endWord, vector<string>& wordList)
    {
        unordered_set<string> hash(wordList.begin(), wordList.end());
        unordered_set<string> vis;
        if(!hash.count(endWord))
        {
            return 0;
        }

        queue<string> q;
        q.emplace(beginWord);
        vis.emplace(beginWord);

        int ret = 1;    //记录单词个数
        while(q.size())
        {
            ret++;
            int sz = q.size();
            while(sz--)
            {
                string t = q.front();
                q.pop();
                for(int i = 0; i < t.size(); i++)
                {
                    string tmp = t;
                    for(char ch = 'a'; ch <= 'z'; ch++)
                    {
                        tmp[i] = ch;
                        if(hash.count(tmp) && !vis.count(tmp))
                        {
                            if(tmp == endWord)
                            {
                                return ret;
                            }
                            q.emplace(tmp);
                            vis.emplace(tmp);
                        }
                    }
                }
            }
        }
        return 0;
    }
};

675. 为高尔夫比赛砍树

题目链接:675. 为高尔夫比赛砍树

题目解析

给我们一个m*n的矩阵:

  • 0表示障碍,无法触碰
  • 1表示地面,可以行走
  • >1的表示有树,可以行走,数值表示树的高度

每次一个上下左右移动一步,如果遇到树,可以决定是否砍伐,砍完为1
砍伐树的顺序必须由低向高砍伐,比如说树的高度有3, 2, 6, 4, 5(树的高度都不同,切至少要砍到一棵树),砍伐的顺序必须是2, 3, 4, 5, 6

从下标[0, 0]出发,返回砍完所有树需要走的最小次数

算法原理

这里就求出每次要到达要砍位置的最短距离即可,即转换成了若干个迷宫问题了

这里还需要知道具体路径顺序,采用一个二维数组,记录位置,然后排一下序

image-20240917220748686

代码实现

class Solution {
public:
    int dx[4] = {1, -1, 0, 0};
    int dy[4] = {0, 0, 1, -1};
    int m = 0;
    int n = 0;
    int cutOffTree(vector<vector<int>>& forest)
    {
        m = forest.size();
        n = forest[0].size();
        
        vector<pair<int, int>> trees;
        for(int i = 0; i < m; i++)
        {
            for(int j = 0; j < n; j++)
            {
                if(forest[i][j] > 1)    trees.push_back({i, j});
            }
        }
        sort(trees.begin(), trees.end(),[&](const pair<int, int>& p1, const pair<int, int>& p2)
        {
            return forest[p1.first][p1.second] < forest[p2.first][p2.second];
        });

        //砍树
        int bx = 0;
        int by = 0;
        int ret = 0;
        for(auto& [a, b] : trees)
        {
            int step = bfs(forest, bx, by, a, b);
            if(step == -1)  return -1;
            ret += step;
            bx = a;
            by = b;
        }
        return ret;
    }
    bool vis[51][51];

    int bfs(vector<vector<int>>& f, int begin_x, int begin_y, int end_x, int end_y)
    {
        if(begin_x == end_x && begin_y == end_y)    return 0;
        queue<pair<int, int>> q;
        memset(vis, 0, sizeof(vis));
        q.push({begin_x, begin_y});
        vis[begin_x][begin_y] = true;
        int step = 0;
        while(q.size())
        {
            step++;
            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];
                    int y = b + dy[i];
                    if(x >= 0 && y >= 0 && x < m && y < n && f[x][y] && !vis[x][y])
                    {
                        if(x == end_x && y == end_y)
                        {
                            return step;
                        }
                        q.push({x, y});
                        vis[x][y] = true;
                    }
                }
            }
        }
        return -1;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2143232.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入理解IP地址分类及子网划分详解

在互联网时代&#xff0c;IP地址是网络通信的基础。无论是访问网站、发送电子邮件&#xff0c;还是进行数据传输&#xff0c;IP地址都扮演着至关重要的角色。本文将详细解析IP地址的分类及子网划分的原理&#xff0c;帮助你更好地理解网络架构及其应用。 一、什么是IP地址 IP…

通信工程学习:什么是TDMA时分多址

TDMA时分多址 TDMA&#xff08;Time Division Multiple Access&#xff0c;时分多址&#xff09;是一种在无线通信中广泛使用的多址接入技术。它通过将时间划分为不重叠的时间帧&#xff0c;并将每个时间帧进一步划分为多个时隙&#xff0c;每个时隙分配给不同的用户或通信系统…

8.JMeter+Ant(基于工具的实现接口自动化,命令行方式)

一、JMeterAnt&#xff08;基于工具的实现接口自动化&#xff09; 如果想要实现自动化&#xff0c;就必须使用命令行。 1.jmeter命令 -n 使用非界面的方式去执行脚本 -t 指定jmeter的脚本位置 -l 生成jtl报告&#xff0c;可以通过查看结果树来解析 -e 生产html格式的报告 -o …

p14 使用阿里云服务器的docker部署NGINX

拉取NGINX的镜像 这里因为之前已经配置过从阿里云的镜像仓库里面拿镜像所以这里直接就执行docker pull nginx拉取NGINX镜像就OK了 运行NGINX镜像 这里执行docker run -d --name nginx01 -p 3344:80 nginx这里3344是服务器访问的端口80是容器内部的端口&#xff0c;可以看到…

Flask-JWT-Extended登录验证, 不用自定义

"""安装:pip install Flask-JWT-Extended创建对象 初始化与app绑定jwt JWTManager(app) # 初始化JWTManager设置 Cookie 的选项:除了设置 cookie 的名称和值之外&#xff0c;你还可以指定其他的选项&#xff0c;例如&#xff1a;过期时间 (max_age)&#xff1…

【贪心】【数据结构-小根堆,差分】力扣2406. 将区间分为最少组数

给你一个二维整数数组 intervals &#xff0c;其中 intervals[i] [lefti, righti] 表示 闭 区间 [lefti, righti] 。 你需要将 intervals 划分为一个或者多个区间 组 &#xff0c;每个区间 只 属于一个组&#xff0c;且同一个组中任意两个区间 不相交 。 请你返回 最少 需要…

vue3 ref的用法及click事件的说明

1、ref可以定义一个简单的属性&#xff0c;也可以是一个复杂的列表、数组等等。 2、为什么要使用 ref&#xff1f;简单的let个变量不行吗&#xff1f;const个变量不行吗&#xff1f; 其实这个跟vue的响应式的系统有关&#xff0c;官方的说明如下&#xff1a; 3、为 ref() 标注…

VMWare中的Centos8:Errors during downloading metadata for repository ‘appstream‘

在VMWare的环境中&#xff0c;安装和部署好Centos8&#xff0c;待设置好网络环境后&#xff0c;安装部署C开发和编译环境&#xff0c;遇到报错&#xff1a; dnf gcc gcc-c -y 解决问题的办法如下, 1. 进入仓库源文件夹&#xff1a;cd /etc/yum.repos.d/ 2. 修改镜像配置{这…

计算机毕业设计 公寓出租系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

Flask-Migrate的使用

组织一个 Flask 项目通常需要遵循一定的结构&#xff0c;以便代码清晰、可维护。下面是一个典型的 Flask 项目结构&#xff1a; my_flask_app/ │ ├── app/ │ ├── __init__.py │ ├── models.py │ ├── views.py │ ├── forms.py │ ├── templat…

微信电脑版聊天图片DAT格式文件转为普通JPG图片

1-7 本文章主要教你如何恢复微信聊天中的聊天图片&#xff0c;主要应用场景是&#xff0c;当你的微信被封号了&#xff0c;或者无法登录了&#xff0c;会导致微信聊天中的聊天图片没办法再打开&#xff0c;如果是重要的图片&#xff0c;那就有损失了&#xff0c;所以有了本文的…

【有啥问啥】弱监督学习新突破:格灵深瞳多标签聚类辨别(Multi-Label Clustering and Discrimination, MLCD)方法

弱监督学习新突破&#xff1a;格灵深瞳多标签聚类辨别&#xff08;Multi-Label Clustering and Discrimination, MLCD&#xff09;方法 引言 在视觉大模型领域&#xff0c;如何有效利用海量无标签图像数据是一个亟待解决的问题。传统的深度学习模型依赖大量人工标注数据&…

探索未来游戏边界:AI驱动的开放世界RPG引擎与UGC平台

在游戏产业的浩瀚星空中,一项革命性的技术正悄然升起,它不仅重塑了游戏开发的传统模式,更将玩家的创造力推向了前所未有的高度。今天,让我们一同走进这个由AI驱动的开放世界RPG游戏引擎与UGC(用户生成内容)平台的奇幻世界,探索其背后的无限可能。 产品定位:AI赋能,重…

AE VM5000 Platform VarioMatch Match Network 手侧

AE VM5000 Platform VarioMatch Match Network 手侧

Vue Application exit (SharedArrayBuffer is not defined)

vite配置 export default defineConfig { server: {cors: true, // 启用 CORSheaders: {Cross-Origin-Opener-Policy: same-origin,Cross-Origin-Embedder-Policy: require-corp,cross-origin-resource-policy: cross-origin}}, } 错误处理 报其它错误&#xff0c;如(Compi…

如何在 CentOS 上安装和使用 Neofetch(图文教程)

Neofetch 是一个用来在命令行界面显示系统信息的工具。它可以展示操作系统、内核版本、CPU、内存、桌面环境、主题、图标、终端等信息&#xff0c;并配合 ASCII 艺术图来美化输出。 一、安装步骤 1、添加yum源 curl -o /etc/yum.repos.d/konimex-neofetch-epel-7.repo https:/…

9.9watershed分水岭分割

实验原理 在计算机视觉中&#xff0c;分水岭算法&#xff08;Watershed Algorithm&#xff09;是一种基于形态学的分割方法&#xff0c;常用于图像分割。OpenCV 提供了 cv::watershed 函数来实现这一算法。分水岭算法的主要思想是将图像视为地形表面&#xff0c;其中像素强度值…

水下目标检测数据集 urpc2021

项目背景&#xff1a; 水下目标检测在海洋科学研究、水下考古、海洋资源勘探等多个领域具有重要的应用价值。由于水下环境的复杂性和多变性&#xff0c;传统的人工检测方法存在诸多限制&#xff0c;自动化检测技术的需求日益增加。URPC2021数据集旨在为水下目标检测提供高质量…

校园社团|基于springBoot的校园社团信息管理系统设计与实现(附项目源码+论文+数据库)

私信或留言即免费送开题报告和任务书&#xff08;可指定任意题目&#xff09; 目录 一、摘要 二、相关技术 三、系统设计 四、数据库设计 五、核心代码 六、论文参考 七、源码获取 一、摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信…

Android 微信,手机文件管理,通过自己软件打开

一、安卓微信关联文件打开&#xff0c;解锁便捷新体验 1.1 直接在微信中点击文件 在工作中&#xff0c;我们经常会通过微信接收各种文件&#xff0c;如文档、表格、PPT 等。安卓微信关联文件打开功能使得我们可以直接在微信中点击文件&#xff0c;快速跳转到相应的应用程序进…