首页 > 其他分享 >广度优先搜素 BFS

广度优先搜素 BFS

时间:2024-07-08 16:11:42浏览次数:22  
标签:Search 遍历 int DFS BFS color 搜素 广度

广度优先搜索 \(\sf\small\color{gray}Breadth\ First\ Search\)

基本思想

广度优先搜索,个人认为,和深度优先搜索对比理解要好得多。
广度优先搜索,亦称层次遍历,指的是在遍历树上按照从上至下,从左至右的次序遍历整棵树。
让我们来看看 BFSDFS 的遍历树吧。

BFS DFS
BFS DFS
从遍历树上来看,这两个算法似乎在代码上搭不着边,可是他们甚至可以用同一串代码!但在开始之前,我们需要来了解一些知识……

核心

基于队列的逐层枚举算法。
\(\hspace{2cm}\)——\(\sf\small\color{black}David\)\(\sf\small\color{EEEEEE}没错,又是他!\)

啥是 \(\sf\color{red}队列\) ?
那为啥要用队列?
先来回顾一下 DFS
DFS 每次找到一个可拓展状态时,就直接进了,无所顾忌。
BFS 就不一样了。他需要把整个层遍历完才可以遍历下一层。
怎么办呢?
\(唉,你先排着队,我先遍历这层的,等你排到了,我再来遍历你。\)
好的,现在,问题不小心解决了……
每一次处理队首,遍历到的新状态就让其入队,直到……
直到什么?
当找到了目标“顾客” \(\sf\small\color{gray}目标态\) ,或者“顾客”走光了\(\sf\small\color{gray}穷举\),遍历就结束了。

加以运用

回家

小 H 在一个划分成了 n×m 个方格的长方形封锁线上。

  • 每次他能向上下左右四个方向移动一格(当然小 H 不可以静止不动), 但不能离开封锁线,否则就被打死了。
  • 刚开始时他有满血 6 点,每移动一格他要消耗 1 点血量。
  • 一旦小 H 的血量降到 0, 他将死去。
  • 他可以沿路通过拾取鼠标(什么鬼。。。)来补满血量。
  • 只要他走到有鼠标的格子,他不需要任何时间即可拾取。
  • 格子上的鼠标可以瞬间补满,所以每次经过这个格子都有鼠标。
  • 就算到了某个有鼠标的格子才死去, 他也不能通过拾取鼠标补满 HP。
  • 即使在家门口死去, 他也不能算完成任务回到家中。
  • 地图上有五种格子:
    0:障碍物。
    1:空地, 小 H 可以自由行走。
    2:小 H 出发点, 也是一片空地。
    3:小 H 的家。
    4:有鼠标在上面的空地。

小 H 能否安全回家?如果能, 最短需要多长时间呢?

如果是 BFS ,那么需要队列里的每一个元素都有四个属性: x 坐标, y 坐标, Hp 血量以及 Lv 层数/时间。
每一轮处理时,都取出队首的元素,向四个方向拓展。
此题特别注意判断顺序。
stlqueue<typename> 挺方便的。

初始化

声明队列、地图、元素结构体、转移数组、出图函数。此处声明Visitint类型是为了避免被这样的数据hack掉。Visit里存路过这里时有过的最大血量。这样就可以保证每次来到这里时血量都是最优的,也就是说只要这里我之前来过,而且之前来的时候有着比现在更多的血量,那么我上次来比我这次来更优。注意此处是严格大于,否则可能会转起圈来。 Hacker
#include<cstdio>
#include<queue>
using std::queue;
int Map[11][11],Visit[11][11],N,M,SX,SY,EX,EY;
const int D[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
struct Point
{
	int x,y;
	int hp;
	int lv;
};
queue<Point> Search;
bool outmap(int x,int y){return (x<1||x>N||y<1||y>M);}

算法实现

初始元素、循环处理、拓展。
让该函数返回答案。
注意判断顺序。

int gohome()
{
	Search.push((Point){SX,SY,6,0});
	while(!Search.empty())
	{
		const Point S=Search.front();
		Search.pop();
		for(int i=0;i<4;i++)
		{
			Point N=(Point){S.x+D[i][0],S.y+D[i][1],S.hp-1,S.lv+1};
			if(outmap(N.x,N.y))		continue;
			if(N.hp<=0)				continue;
			if(Map[N.x][N.y]==0)	continue;
			if(Map[N.x][N.y]==3)	return N.lv;
			if(Map[N.x][N.y]==4)	N.hp=6;
			if(Visit[N.x][N.y]>=N.hp)continue;
			Visit[N.x][N.y]=N.hp;
			Search.push(N);
		}
	}
	return -1;
}

完整代码

#include<queue>
using std::queue;
int Map[11][11],Visit[11][11],N,M,SX,SY,EX,EY;
const int D[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
struct Point
{
	int x,y;
	int hp;
	int lv;
};
queue<Point> Search;
bool outmap(int x,int y){return (x<1||x>N||y<1||y>M);}
void scanmap()
{
	for(int i=1;i<=N;i++)
		for(int j=1;j<=M;j++)
		{
			scanf("%d",&Map[i][j]);
			if(Map[i][j]==2)		SX=i,SY=j;
			else if(Map[i][j]==3)	EX=i,EY=j;
		}
}
int gohome()
{
	Search.push((Point){SX,SY,6,0});
	while(!Search.empty())
	{
		const Point S=Search.front();
		Search.pop();
		for(int i=0;i<4;i++)
		{
			Point N=(Point){S.x+D[i][0],S.y+D[i][1],S.hp-1,S.lv+1};
			if(outmap(N.x,N.y))		continue;
			if(N.hp<=0)				continue;
			if(Map[N.x][N.y]==0)	continue;
			if(Map[N.x][N.y]==3)	return N.lv;
			if(Map[N.x][N.y]==4)	N.hp=6;
			if(Visit[N.x][N.y]>=N.hp)continue;
			Visit[N.x][N.y]=N.hp;
			Search.push(N);
		}
	}
	return -1;
}
int main()
{
	scanf("%d%d",&N,&M);
	scanmap(); 
	printf("%d",gohome());
	return 0;
} 

说些别的……

为什么 DFSBFS 都是搜索,可是代码却大相径庭,为什么呢?
其实 DFS 也可以这么写,只不过用的不是队列。
\(\sf\color{red}栈\)

算法优劣

BFS 主要优在时间。
看看这张图, BFS 枚过的面积只是 DFS 的一半。
\(\sf\small\color{gray}BFS比DFS的图枚得快一些,所以不能看时间,要看枚过的面积。\)

BFS DFS
BFS DFS
可以看到, BFS 时间较平均,而 DFS 很大程度上取决于终点的位置。

完结散花

标签:Search,遍历,int,DFS,BFS,color,搜素,广度
From: https://www.cnblogs.com/PCwqyy/p/18290090/BreadthFirstSearch

相关文章

  • 从零开始学数据结构系列之第四章《 广度优先遍历BFS》
    文章目录广度优先遍历(BFS)概念广度优先遍历算法步骤总代码往期回顾广度优先遍历(BFS)概念​  广度优先遍历(BreadthFirstSearch),又称为广度优先搜索,简称BFS。​  如果说图的深度优先遍历类似树的前序遍历,那么图的广度优先遍历就类似于树的层序遍历了。​ ......
  • C#实现DFS和BFS
    以图示为例:Noderoot=newNode("A",newNode("B",newNode("C"),newNode("D")),newNode("E",newNode("F"),newNode("......
  • 12.优化算法之队列+宽搜(BFS)
    BFS——广度优先算法(BreadthFirstSearch)-CSDN博客1.N叉树的层序遍历(广度优先搜索)429.N叉树的层序遍历-力扣(LeetCode)classSolution{publicList<List<Integer>>levelOrder(Noderoot){List<List<Integer>>ret=newLinkedList<>();......
  • elasticsearch 全文搜素 query_string 搭配其他条件
    elasticsearch全文搜素query_string搭配其他条件{"query":{"bool":{"must":[{"term":{"item_type":"question"......
  • 【广度优先搜索 深度优先搜索 图论】854. 相似度为 K 的字符串
    本文涉及知识点广度优先搜索深度优先搜索图论图论知识汇总深度优先搜索汇总C++BFS算法LeetCode854.相似度为K的字符串对于某些非负整数k,如果交换s1中两个字母的位置恰好k次,能够使结果字符串等于s2,则认为字符串s1和s2的相似度为k。给你两个字母......
  • 网络空间搜素引擎
    引子​ 360水滴直播时间​ 思考​ 除了网络摄像头之外,网络空间还包括什么?​ 黑客是怎么找到某一个网络设备的?什么是网络空间?搜索引擎1996---数字图书馆1998---谷歌诞生---网页发展图片音乐声音电视剧……进一步网络系统CDN​CMSIDS......
  • 搜素引擎收集信息
    GoogleHacking​ 2002​ JohnnyLong​ GoogleDorksGoogleHacking运算符完全匹配"网络安全工程师"任意字词批发OR特价不包含burpsuite-xxx数字范围number..number高级语法只搜索某个网站的内容site:zhihu.com网页的内容包括allintext:PoweredbyDis......
  • 6.14BFS,DFS
    7-1列出联通集给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集。假设顶点从0到N−1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。输入格式:输入第1行给出2个整数N(0<N≤10)和E,分别是图的顶点数和边数。随后E行,每行给出......
  • BFS(广度优先搜索)优化技巧 — 双向遍历
    BFS优化技巧—双向遍历在之前我发过动态规划框架与动态规划的优化技巧—空间压缩,类似的,BFS框架也有相应的优化技巧双向遍历。从技巧的名字就可以看出,双向遍历指的就是从起点开始找终点的同时,也从终点开始找起点,一旦两个寻找过程出现交集,那么起点到终点的路径也就找出......
  • BFS实现图的点的层次-java
    加强对广度优先搜索的理解,其实就是主要的3个步骤,外加数组模拟单链表是基础,要搞懂。目录前言一、图中点的层次二、算法思路1.广度优先遍历 2.算法思路三、代码如下1.代码如下(示例):2.读入数据:3.代码运行结果:总结前言加强对广度优先搜索的理解,其实就是主要的3个步......