宽度优先搜索算法(BFS)详解(超级详细讲解,附有大图)

news2024/9/25 23:21:21

目录

一.宽度优先搜索(BFS)是什么?

二.图解宽搜(BFS)

三.对比与发现

四。工具——队列

 五.模板

六.最后


一.宽度优先搜索(BFS)是什么?

百度百科这样说:

宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。

过于理论性,不过说出了核心:

 它是一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。

 也有人这样说:

就是从根结点位置开始遍历,遍历结束后依次遍历与根节点相邻的点,相邻点遍历结束后继续遍历上轮第一个遍历结点的相邻的未遍历的点,直至所有的点都遍历结束。

generalKnowledge/基础算法/广度优先搜索.md · jimmyflower6/中山一中初中部信息竞赛 - Gitee.com

 这个说的比较好,但仍然有一点生硬。

简单来说,就是:

宽度优先搜索是一种对图进行搜索的算法。假设我们一开始位于某个顶点(即起点),此 时并不知道图的整体结构,而我们的目的是从起点开始顺着边搜索,直到到达指定顶点(即终 点)。在此过程中每走到一个顶点,就会判断一次它是否为终点。广度优先搜索会优先从离起点 近的顶点开始搜索。

下面,我将用步骤图的方式,向大家介绍这种方法。


二.图解宽搜(BFS)

 A为起点,G为终点。一开始我们在起点A上,此时并不知道G在哪里。

将可以从A直达的三个顶点B、C、D设为下一步的候补顶点。 

从候补顶点中选出一个顶点。优先选择最早成为候补的那个顶点,如果多个顶点同时成为候补,那么可以随意选择其中一个。 (优先选择最早成为候补的那个顶点,这是一种“先进先出”的方式,后面会讲到)

此处 B、C、D 同时成为候补,所以我们随机选择了最左边的顶点B。 

移动到选中的顶点B上。此时我们在B上, 所以B变为红色,同时将已经搜索过的顶点变为橙色。

此处,候补顶点是用“先入先出”(FIFO)的方式来管理的,因此可以使用“队列”这个数据结构。(这个结构将会在后面讲解,请往下翻)

将可以从B直达的两个顶点E和F设为候补 顶点。

此时,最早成为候补顶点的是C和D,我们选择了左边的顶点C。 

移动到选中的顶点C上。

将可以从C直达的顶点H设为候补顶点。 

重复上述操作直到到达终点,或者所有的顶点都被遍历为止。 

这个示例中的搜索顺序为 A、B、C、D、E、F、 H、I、J、K。 

完成了从A到I的搜索,现在在顶点J处。 

到达终点G,搜索结束。

补充说明:由上可以知道,广度优先搜索的特征为从起点开始,由近及远进行广泛的搜索。因此,目标顶点离起点越近,搜索结束得就越快。


三.对比与发现

DFS和BFS的区别
bfs 遍历节点是先进先出,dfs遍历节点是先进后出
bfs是按层次访问的,dfs 是按照一个路径一直访问到底,当前节点没有未访问的邻居节点时,然后回溯到上一个节点,不断的尝试,直到访问到目标节点或所有节点都已访问。
bfs 适用于求源点与目标节点距离最近的情况,例如:求最短路径。dfs 更适合于求解一个任意符合方案中的一个或者遍历所有情况,例如:全排列、拓扑排序、求到达某一点的任意一条路径。

不过,宽度优先搜索(BFS)的先进先出如何实现呢?这里,我们运用了一个数据结构——队列。 


四。工具——队列

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

我们可以用双指针标记一下,通过front指针与rear指针,对队头和队尾进行标记,然后只允许在front、rear指针的位置进行增删改查,那么这样便实现了对数组的受限。这是一种运用数组的数据结构对队列的模拟。初学者建议先用这种方式熟悉队列。

具体操作:

/*
    通常将front赋值为0,rear赋值为-1
    方便后续进队、出队以及取队首元素
 */
int a[100], front=0, rear=-1;

// 进队
a[++rear] = 10;

// 出队
front++

// 取队首元素
a[front]

// 取队尾元素
a[rear]

// 判断是否为空队
if(front > rear)
    cout << "该队列为空队";

不过,到了后期,为了节省时间,我们可以直接用c++自带的STL容器来完成操作。

具体操作如下:

// 导入queue包
#include<queue>

// 申明一个queue对象
// 填入你想装填的数据类型
queue<int> qu;

// 进队
int a = 10;
qu.push(a);

// 出队,无返回值
qu.pop();

// 取队首元素
int front = qu.front();

// 取队尾元素
int rear = qu.back();

// 队是否为空
if(qu.empty()) {
    cout << "该队列为空队";
}

// 队大小,返回int
qu.size();

 五.模板

BFS的题目是有一套明显模板的,不信,我们来看看。(将展示核心代码)

八数码问题:


    while(!q.empty())//q非空,可以走
    {
        for(int i=0;i<4;i++)//四个方向
        {
            ma ac=q.front();
            int nx = ac.x0 + dx[i];
            int ny = ac.y0+ dy[i];
            if(nx>=1&&ny>=1&&nx<=3&&ny<=3)
            {
                swap(ac.a[ac.x0][ac.y0],ac.a[nx][ny]);
                ac.x0=nx;
                ac.y0=ny;
                //将0与目标数交换
                ac.ans++;//步数加1
                ac.kt=kt(ac);
                //康托判重
                 if (!flag[ac.kt])
                {
                    flag[ac.kt] = 1;
                    q.push(ac);
                    //加入队列
                    if(ac.kt==mo.kt)
                    { 
                        printf("%d",q.back().ans);
                        exit(0);
                    }
                }
            }
        }
        q.pop();
        //弹出已遍历完所有情况的矩阵
    }

海上救援任务:

		while(!q.empty())
		{
			for(int i=0;i<4;i++)
			{
				node ne;
				ne.x=q.front().x+dx[i],ne.y=q.front().y+dy[i];
				if(bo[ne.x][ne.y]==0&&ne.x>=0&&ne.y>=0&&ne.x<=n&&ne.y<=m&&a[ne.x][ne.y]==1)
				{
					ne.ans=q.front().ans+1;
					bo[ne.x][ne.y]=1;
					q.push(ne);
					if(ne.x==xe.x&&ne.y==xe.y)
					{
						flag=true;
						printf("%d\n",q.back().ans);
						break;
					}
				}
			}
			if(flag) break;
			q.pop(); 
		}

 巧妙取量:

    while(scanf("%d%d%d%d",&t.a[1],&t.a[2],&t.a[3],&k)!=EOF)//多组数据
    {
        flag=false;
        memset(bo,0,sizeof(bo));
         
    	bo[t.a[1]][t.a[2]][t.a[3]]=1;
    	p.ans=0;
    	p.a[1]=t.a[1];
    	p.a[2]=p.a[3]=0;
    	q.push(p);
     	if(q.front().a[1]==k||q.front().a[2]==k||q.front().a[3]==k)
    	{
    	    printf("yes\n%d\n",0);
            continue;
    	}//特判 
    	while(!q.empty())
    	{
        	for(int i=1;i<=3;i++)
        	{
          		if(q.front().a[i]>0)
            	{
                	for(int j=1;j<=3;j++)
                	{
                    	node sy;
                    	sy=q.front();
                    	sy.ans ++;
                    	if(i!=j)
                    	{
                        	int T=t.a[j]-sy.a[j];
                        	if(sy.a[i]>T)
                        	{
                            	sy.a[j]=t.a[j];
                            	sy.a[i]=sy.a[i]-T;
                        	}
                        	else
                        	{
                            	sy.a[j]+=sy.a[i];
                            	sy.a[i]=0;
                        	}
                        	if(!bo[sy.a[1]][sy.a[2]][sy.a[3]])
                        	{
                            	bo[sy.a[1]][sy.a[2]][sy.a[3]]=1;
                            	if(sy.a[1]==k||sy.a[2]==k||sy.a[3]==k)
                            	{
                                	flag=true;
                            	}
                            	q.push(sy);
                        	}
                    	}
                	}
            	}
          
        	}//遍历每一种倒法 
        if(flag) break;
        q.pop();
    	}
    	if(flag)
    	{
        	printf("yes\n%d\n",q.back().ans);
    	}
    	else
    	{
        	printf("no\n");
    	}
    	while(!q.empty())
    	{
        	q.pop();
    	}
    }

我选了几道没那么相似的题目,但仔细一看,架构都是一样的。

用步骤图可表示为:

 而用伪代码,则是这样表示:

int BFS(Node start, Node target) {
    入队(初始状态);
    visited[初始状态] = true;
    while(!空队) {
        for() { // 状态转换
            Node node = 队首元素;

            对node的处理,生成新node状态;

            if (visited[node] == true)
                continue;
            if (node == target) {
                输出答案;
                return 0;
            }
            v[node] = true;
            入队(node);
        }
    }
    出队();
}

这,就是BFS问题的模板!!!

六.最后

没什么,如果喜欢的话,给个三连吧!您的支持是我最大的动力!

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

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

相关文章

一文讲透:质量管理的历史

&#xff08;本文摘自《软件质量保证与管理&#xff08;第2版&#xff09;》&#xff0c;清华大学出版社&#xff0c;2020&#xff09;1875年泰勒制诞生&#xff0c;意味着科学管理的开始&#xff0c;最初的质量管理也就是将检验活动与其他职能分离&#xff0c;出现了专职的检验…

2022-2023年中国数字经济投融资及创新展望研究报告(附下载链接)

省时查报告-专业、及时、全面的行研报告库省时查方案-专业、及时、全面的营销策划方案库【免费下载】2022年12月份热门报告盘点罗振宇2023年跨年演讲PPT原稿吴晓波2022年年终秀演讲PPT原稿2023年&#xff0c;如何科学制定年度规划&#xff1f;《底层逻辑》高清配图清华大学256页…

AF647 DBCO荧光染料,AF647 DBCO,Alexa Fluor 647 DBCO,AF-647, 二苯并环辛

一、产品描述&#xff1a;Alexa Fluor 647是一种明亮且可感光的远红色染料&#xff0c;其激发非常适合633 nm激光线。Alexa Fluor 647染料用于在成像和流式细胞仪中产生稳定的信号&#xff0c;在pH 4到pH 10之间为水溶性且对pH不敏感。这种长波长Alexa Fluor 染料的荧光肉眼看不…

什么是元器件二筛,为何要二筛,如何二筛,二筛的要求与分级要点总结

&#x1f3e1;《电子元器件学习目录》 目录1&#xff0c;什么是二筛2&#xff0c;为何要二筛3&#xff0c;如何进行二筛4&#xff0c;二筛的要求5&#xff0c;二筛的分级6&#xff0c;总结1&#xff0c;什么是二筛 电子元器件测试筛选即元器件二次筛选&#xff0c;又被简称为二…

Spring @Autowired 用法

Spring Autowired 用法首先看下Component举例 1 :举例 2 :验证是否调用的是默认构造器如何&#xff0c;在启动的时候执行有参数的构造函数&#xff1f;&#xff1f;&#xff0c;这就要看Autowired注解了&#xff01;Autowired注解首先看下Component 在类级别上添加了Component…

Flask入门教程(视频教程笔记)

初始化flask项目 前面的python环境之类的就不说了。 该博客是看 Flask 入门 这个视频教程写的笔记&#xff0c;如果你想入门一下Flask&#xff0c;可以看看这个课&#xff0c;虽然简短&#xff0c;但是入门部分讲的很好&#xff0c;同时可以利用这篇博客复习复习。如果你想了解…

二、MES的生态链

1、MES功能模块图1、 符合MESA/ISA-95标准&#xff0c;基于SOA架构&#xff0c;技术架构与业务架构分离&#xff0c;实现多厂分布式部署具备标准化模型组件&#xff0c;可根据客户需求选取标准组件、或调整业务对象脚本&#xff0c;组合成全新的业务组件&#xff0c;实现企业ME…

电动汽车热管理方案

热管理技术作为汽车节能、提高经济性和保障安全性的重要措施&#xff0c;在汽车研发过程中具有重要作用。传统燃油汽车的热管理系统主要包括发动机、变速器散热系统和汽车空调&#xff0c;而电动汽车的热管理系统在燃油汽车热管理架构的基础之上&#xff0c;又增加了电机电控热…

【Python百日进阶-数据分析】Day228 - plotly的图表的变换

文章目录一、过滤二、分组三、聚合四、多重转换4.1 Filter and Group By4.2 Filter and Aggregate4.3 所有变换4.4 Dash中的应用一、过滤 如何通过 Plotly 在 Python 中使用过滤器。 注意 transforms在 v5 中已弃用&#xff0c;plotly将在未来版本中删除 import plotly.io as…

分享97个PHP源码,总有一款适合您

PHP源码 分享97个PHP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 97个PHP源码下载链接&#xff1a;https://pan.baidu.com/s/1OUa-rpzDK6CG8oj6BLZSTw?pwdxdt2 提取码&#xff…

上传ipa到appstore的步骤说明

上传ipa到appstore&#xff0c;首先你要有苹果开发者账号&#xff0c;一定要使用你自己的苹果开发者账号的证书打包&#xff0c;才能将ipa上传到你自己的苹果账号&#xff0c;才能提交到app store里。假如你还没有苹果开发者账号&#xff0c;或者你有证书但不是你自己账号生成的…

ES6ES6

ES8-ES8 新特性 4.1.async 和 await async和await 两种语法结合可以让异步代码像同步代码一样 4.1.1.async函数 async函数的返回值为 promise 对象&#xff0c; 2.promise 对象的结果由 asynt函数执行的返回值决定 4.1.2await表达式awaity必须写在 async 函数中 2.await 右侧…

Rockchip开发系列 - 3.2.引脚配置默认上拉下拉

By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 目录 返回总目录:Rockchip开发系列 - 总目录 开发过程中发现rk3568-linux.dtsi中耳机监测应急一直是处于低电平状态: 这个gpio表格也说…

【MyBatis】| 在WEB中应⽤MyBatis(使⽤MVC架构模式)

目录 一&#xff1a;在WEB中应⽤MyBatis&#xff08;使⽤MVC架构模式&#xff09; 1. 前期准备 2. 核心代码实现 3. 事务控制 4. 三大对象的作用域 一&#xff1a;在WEB中应⽤MyBatis&#xff08;使⽤MVC架构模式&#xff09; 目标&#xff1a; ①掌握mybatis在web应⽤中怎…

【闪电侠学netty】第9章 实现客户端登录

【Netty】读书笔记 - 跟闪电侠学 1. 内容概要 1.1 总结 1.1.1 逻辑处理器 ChannelHandler&#xff08;详见 第11章 Pipeline与ChannelHandler&#xff09; 1.1.2 编程小技巧 public class PacketCodeC {...public static final PacketCodeC INSTANCE new PacketCodeC();.…

spring学习-第一讲-beanFactory与ApplicationContext

BeanFactory与ApplicationContext区别 创建一个springboot项目&#xff0c;对这个函数的main函数来进行执行。 ConfigurableApplicationContext context SpringApplication.run(BeanFactoryApplicationContextStudyApplication.class, args); 很明显&#xff0c;Configurabl…

“互联网+”六年,云徙科技打造数字化经营增长“头牌”

2022年底的全面开放结束了三年疫情&#xff0c;三年来以消费零售为代表的商业领域发生了深刻变局。根据2022年8月的第50次中国互联网络发展状况统计报告&#xff0c;互联网推动网民消费模式变迁&#xff1a;在消费场景方面&#xff0c;从线上消费逐步转变为线上线下融合消费&am…

软件安装教程-Vivado2018.3/ISE14.7/Modelsim10.5/Keil5/AD18/Cadence17.2/CAD2016

硬件工程师软件安装教程 1.Vivado2018.3安装教程 本文的主要内容是介绍 Vivado 2018.3 版本(提取码&#xff1a;ebdx)的安装步骤及其 license(提取码: 6xkh) 的获取与加载。 本文学习自《【ALINX】FPGA ZYNQ视频教程——AX7010/AX7020教程——基础部分》 首先下载安装包&…

【Unity3D】基于模板测试和顶点膨胀的描边方法

1 前言 选中物体描边特效 中介绍了基于模板纹理模糊膨胀的描边方法&#xff0c;该方法实现了软描边&#xff0c;效果较好&#xff0c;但是为了得到模糊纹理&#xff0c;对屏幕像素进行了多次二次渲染&#xff0c;效率欠佳。本文将介绍另一种描边方法&#xff1a;基于模板测试和…

简单使用tomcat查看版本信息等·

Tomcat 是什么 &#xff1f;1.Apache Tomcat 是由 Apache Software Foundation&#xff08;ASF&#xff09;开发的一个开源 Java WEB 应用服务器。2.由于 Tomcat 是由 Java 语言实现的&#xff0c;因此需要运行在 Java 虚拟机上&#xff0c;所以使用前要先安装 JDK&#xff0c;…