广搜(BFS)

在我们日常刷题的过程中,我们会通过遍历来获取自己想要的数组,搜索算法就是典型的一种。
而搜索算法中也分深搜(DFS),广搜(BFS),而今天,我们来说说广搜。

什么是广搜

广搜全称叫广度优先搜索,或叫宽度优先搜索,简称BFS。人如其名,他不像深搜一路干到底,而是一层一层的搜索,如图在这里插入图片描述
当然,广搜有很多种,这只是广搜和二叉树的结合,不过大体就是像这样,一层一层的搜索

广搜原理及其伪代码

在这里插入图片描述
如上图,是广搜全过程(无重复搜索)
我来给大家解读下
刚开始时是1号位,由于广搜是一层层的搜索,所以搜完2号位后不能着急搜2号位的其他点,而是要把1号位能搜完的全部搜完,于是我们搜3号位。这时1号位搜完了,所以我们可以搜其他位了,我们可以先搜3号位,同搜1号位,4号位和5号位搜完了…直到最后61号位和60号位搜完了,到62号位了,最后结束。
【分析】我们口述时是直接更换搜索位置的,这对于我们人来说很轻松,但是大家想过没有,这用c++该怎么实现呢?其实很简单,用数组模拟就行,用一个变量记录现在搜的是谁,如果搜完了,就跳到下一位。
代码如下(注:此代码只是表达思路,并不是伪代码):

int ab[1050];
int head=0;
if(搜完了){
head++;
} 
else{for(){继续搜索 加入数据}
}

不过虽然数组模拟通俗易懂,但对于某些情很极端,如你要加入1千万的数据,数组就存不下了,对于这种数组存不下的情况该怎么办呢?这时,我们得先冷静下来,思考,为什么数组存不下,就是因为删除的部分没有删除数据,只要把前面的数删了,问题就解决了,哎!恰好c++的STL里面的队列可以解决此问题,而且和数组差不多,甚至会比数组模拟更好用
好,看代码(注:此代码只是表达思路,并不是伪代码

queue<int>q;
初始化
如果队列不为空{int f=q.front();q.pop();//弹出if(满足答案){return ...; } 搜索{ if(满足条件){q.push(...); } } 
}

好的我们终于分析完了,总结:广搜一般用队列,如果数据量较小,就用数组模拟(尽量用队列),
如果队列不为空(就是没搜完)就继续搜,搜完一个弹出队列,如果满足答案就返回(BFS函数大多是用返回值int),否则慢慢搜答案。对于搜到的答案如果满足条件就入队
好的伪代码如下

int bfs(变量){queue<类型>q;初始化while(!q.empty()){  //队列不为空 类型 f=q.front(),q.pop();if(判断能否返回){return ;  //返回 } for(枚举(搜索)){判断{初始化搜索结果 q.push(...);  //加入 如果能返回就直接返回 } }} return -1;  //返回不了 
}

广搜经典例题

知道广搜原理后就可以上手了!

1330:【例8.3】最少步数

【题目描述】
在各种棋中,棋子的走法总是一定的,如中国象棋中马走“日”。有一位小学生就想如果马能有两种走法将增加其趣味性,因此,他规定马既能按“日”走,也能如象一样走“田”字。他的同桌平时喜欢下围棋,知道这件事后觉得很有趣,就想试一试,在一个(100×100)的围棋盘上任选两点A、B,A点放上黑子,B点放上白子,代表两匹马。棋子可以按“日”字走,也可以按“田”字走,俩人一个走黑马,一个走白马。谁用最少的步数走到左上角坐标为(1,1)的点时,谁获胜。现在他请你帮忙,给你A、B两点的坐标,想知道两个位置到(1,1)点可能的最少步数。

【输入】
A、B两点的坐标。

【输出】
最少步数。

【输入样例】
12 16
18 10
【输出样例】
8
9

【分析】很明显是道广搜题(因为我们需要多重考虑),重!!!:我们在搜索时一定要方向数组,而且也要标记数组,毕竟会走重复路就会超时(亲测)。这时我们也要用到结构体了,因为考虑到了步数,位置,我们需要结构体里的变量标记,不然得至少开三维数组

#include<bits/stdc++.h>
using namespace std;
int xy[][2]={{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2},{2,2},{2,-2},{-2,-2},{-2,2}};
//方向数组与标记数组
int flag[105][105];
//结构体
struct node{int x,y;int step;//步数
};
int bfs(int x,int y){queue<node>q;//初始化node cs;   flag[x][y] = 1;cs.step = 0 , cs.x = x , cs.y = y;q.push(cs);while(!q.empty()){node f = q.front(); q.pop();  if(f.x == 1 && f.y == 1){return f.step;}for(int i = 0;i < 12;i++){//搜索int xx = f.x + xy[i][0];int yy = f.y + xy[i][1];//数据判断if(xx >= 1 && xx <= 100 && yy >= 1 && yy <= 100 && flag[xx][yy] == 0){node nw;flag[xx][yy] = 1;nw.x = xx , nw.y = yy , nw.step = f.step + 1;if(xx == 1 && yy == 1){return nw.step;}q.push(nw);}}}
}
int main()
{
int x,y;
cin >> x >> y;
cout << bfs(x , y) << endl;
memset(flag,0,sizeof(flag));  //调用俩次,flag清0
cin >> x >> y;
cout << bfs(x , y) << endl;return 0;
}

1254:走出迷宫

【题目描述】
当你站在一个迷宫里的时候,往往会被错综复杂的道路弄得失去方向感,如果你能得到迷宫地图,事情就会变得非常简单。

假设你已经得到了一个n×m
的迷宫的图纸,请你找出从起点到出口的最短路。

【输入】
第一行是两个整数n
和m
(1≤n,m≤100
),表示迷宫的行数和列数。

接下来n
行,每行一个长为m
的字符串,表示整个迷宫的布局。字符‘.’表示空地,‘#’表示墙,‘S’表示起点,‘T’表示出口。

【输出】
输出从起点到出口最少需要走的步数。

【输入样例】
3 3
S#T
.#.

【输出样例】
6
【分析】经典广搜,方向数组,标记数组,大力枚举,结构体一条龙

#include<bits/stdc++.h>
using namespace std;
int n,m;
int flag[105][105];  //标记数组
char mp[105][105];
int dx[] = {0 , 0 , 1 , -1};  //方向数组
int dy[] = {1 , -1 , 0 , 0};
struct node{   //结构体int x,y;int step;
};
int bfs(int lx,int ly,int zx,int zy){queue<node>q;//初始化node g; flag[lx][ly] = 1;g.x = lx,g.y = ly,g.step = 0;q.push(g);while(!q.empty()){node f = q.front();q.pop();if(f.x == zx && f.y == zy){  //答案判断return f.step;}//大力出奇迹for(int i = 0;i < 4;i++){int fx = f.x + dx[i];int fy = f.y + dy[i];//范围判断if(fx >= 1 && fx <= n && fy >= 1 && fy <= m && flag[fx][fy] == 0 && mp[fx][fy] != '#'){flag[fx][fy] = 1;node now;now.x = fx , now.y = fy , now.step = f.step + 1;q.push(now);if(fx == zx && fy == zy){  //答案判断return f.step + 1;}}}}return -1;
}
int main()
{
cin >> n >> m;
int sx,sy,zx,zy;
for(int i = 1 ;i <= n;i++){for(int j = 1;j <= m;j++){cin>>mp[i][j];if(mp[i][j] == 'S'){   //拿下起点位置sx=i;sy=j;}if(mp[i][j] == 'T'){   //拿下终点位置zx=i;zy=j;}}
}
cout << bfs(sx,sy,zx,zy);return 0;
}

数字转换

给你两个数s,t, 从s开始,每次从小于当前数的质因子中挑选一个数加给当前数,问最少加几次能到达t

输入
第一行输入一个整数T,表示测试组数

接下来T行每行两个整数s,t

输出
对于每组测试数据输出一个最小步数,如果无法到达,输出-1

具体格式见样例输出

样例
输入 1
2
6 12
6 13
输出 1
Case 1: 2
Case 2: -1
提示
约定:
T<=500,1<=s<=100,1<=t<=1000
【分析】这里已经不是搜索题了,但是仍要用广搜的思想(一层层枚举),不过值得注意的是,这里需要用素数筛法+广搜

#include<bits/stdc++.h>
using namespace std;
int s,t;
const int N=1010;
int flag[N];
void init(){   //素数筛flag[1]=1;for(int i=2;i<N;i++){if(flag[i]==0){for(int j=i+i;j<N;j+=i){flag[j]=1;}}}
} 
int vis[N],dis[N];//vis标记数组,dis答案数组
int bfs(int s,int t){queue<int>q;q.push(s);vis[s]=1;dis[s]=0;while(!q.empty()){int f=q.front();q.pop();if(f==t){return dis[t];}for(int i=2;i*i<=f;i++){if(f%i==0&&flag[i]==0){int x=i;if(f+x<=t&&vis[f+x]==0){vis[f+x]=1;q.push(f+x);dis[f+x]=dis[f]+1;}}if(f%i==0&&f/i!=i&&flag[f/i]==0){int x=f/i;if(f+x<=t&&vis[f+x]==0){vis[f+x]=1;q.push(f+x);dis[f+x]=dis[f]+1;}}}}return -1;
}
int main()
{
init();
int T,ca=1;
cin>>T;
while(T--){
memset(vis,0,sizeof(vis));
memset(dis,0,sizeof(dis));  //归0
cin>>s>>t;
cout<<"Case "<<ca<<": "<<bfs(s,t)<<"\n";
ca++;
}return 0;
} 

营救计划

易错题警告!!!
在一个n∗m的迷宫里,有一个萌新被困住了,你作为一个久经码场的战士,决定去营救萌新。地图中还会有一些守卫,你必须打败守卫才能通过守卫所在的位置,打败守卫需要花费1分钟,移动一步需要花费一分钟,每次你只能往上下左右某个方向移动一步。问你最少需要花费多少时间才能救到萌新。

输入
第一行输入两个整数 n,m

接下来n行每行输入m个字符

'#'代表障碍物,无法直接通过

'.'代表空地,可以直接通过

'G’代表守卫,你需要打败他才能通过

'M’代表萌新所在的位置

'@'表示你所在的位置

输出
如果可以营救到萌新,就输出最少需要花费的分钟数

如果不可以,输出“You can’t save Mengxin”

样例
输入 1
7 8
#.#####.
#.M#…@.
#…#G…
…#…#.#
#…##…
.#…

输出 1
13
输入 2
2 2
M.
G@
输出 2
2
提示
1<=n,m<=200
【分析】经典广搜,分析什么?于是,一顿小连招,你会,发现错了!为什么错了呢,这是经典广搜,不过是他却是考到了广搜->状态,我们只需分类讨论就行了

#include<bits/stdc++.h>
using namespace std;
const int N=222;
int n,m;
int dis[N][N][2]; //状态数组
int vis[N][N][2];
char mp[N][N];
int dx[]={1,0,-1,0};
int dy[]={0,1,0,-1};
struct node{  int x,y,flag;
};
int bfs(int sx,int sy){queue<node>q; node t;t.x=sx;t.y=sy;t.flag=0;q.push(t);vis[sx][sy][1]=0;dis[sx][sy][1]=0;while(!q.empty()){node f=q.front();q.pop();if(mp[f.x][f.y]=='G'&&f.flag==0&&vis[f.x][f.y][1]==0){//特判dis[f.x][f.y][1]=dis[f.x][f.y][0]+1;vis[f.x][f.y][1]=1;f.flag=1;q.push(f);continue;}for(int i=0;i<4;i++){node g;int nowx=f.x+dx[i];int nowy=f.y+dy[i];g.x=nowx;g.y=nowy;if(nowx<0||nowx>=n||nowy<0||nowy>=m||mp[nowx][nowy]=='#'){continue;}if(mp[nowx][nowy]=='G'){//状态情况考虑if(vis[nowx][nowy][0]==0){vis[nowx][nowy][0]=1;dis[nowx][nowy][0]=dis[f.x][f.y][f.flag]+1;g.flag=0;q.push(g);}}else if(mp[nowx][nowy]=='M'){return dis[f.x][f.y][f.flag]+1;}else{if(vis[nowx][nowy][1]==0){vis[nowx][nowy][1]=1;dis[nowx][nowy][1]=dis[f.x][f.y][f.flag]+1;g.flag=1;q.push(g);}}}}return -1;
}
int main()
{cin>>n>>m;
int sx,sy;
for(int i=0;i<n;i++){
cin>>mp[i];for(int j=0;j<m;j++){	if(mp[i][j]=='@'){sx=i;sy=j;}}
}
int ret=bfs(sx,sy);
if(ret==-1){cout<<"You can't save Mengxin";
}
else{cout<<ret;
}return 0;
} 

完结!!!撒花!!!

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Stwo:基于Circle STARK和M31的下一代STARK证明系统

1. 引言 StarkWare团队和Polygon Labs团队&#xff0c;历时数月&#xff0c;构造了基于Mersenne素数域M31的Circle STARK协议&#xff0c;通过使用M31 over a circle&#xff0c;可基于任意有限域构造高效STARKs&#xff0c;具体见2024年2月19日论文《Circle STARKs》。 基于…

ES6 | (二)ES6 新特性(下) | 尚硅谷Web前端ES6教程

文章目录 &#x1f4da;迭代器&#x1f407;定义&#x1f407;工作原理&#x1f407;自定义遍历数据 &#x1f4da;生成器函数&#x1f407;声明和调用&#x1f407;生成器函数的参数传递&#x1f407;生成器函数案例 &#x1f4da;Promise&#x1f4da;Set&#x1f407;Set的定…

Carla自动驾驶仿真九:车辆变道路径规划

文章目录 前言一、关键函数二、完整代码效果 前言 本文介绍一种在carla中比较简单的变道路径规划方法&#xff0c;主要核心是调用carla的GlobalRoutePlanner模块和PID控制模块实现变道&#xff0c;大体的框架如下图所示。 一、关键函数 1、get_spawn_point(),该函数根据指定r…

Docker容器资源限制与优化全攻略:CPU、内存、磁盘IO一网打尽

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Docker入门到精通》 《k8s入门到实战》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、docker容器技术概述 2、资源限制与优化的重要性 …

C++设计模式_创建型模式_工厂方法模式

目录 C设计模式_创建型模式_工厂方法模式 一、简单工厂模式 1.1 简单工厂模式引入 1.2 简单工厂模式 1.3 简单工厂模式利弊分析 1.4 简单工厂模式的UML图 二、工厂方法模式 2.1 工厂模式和简单工厂模式比较 2.2 工厂模式代码实现 2.3 工厂模式UML 三、抽象工厂模式 3.1 战斗场景…

IDEA的安装教程

1、下载软件安装包 官网下载&#xff1a;https://www.jetbrains.com/idea/ 2、开始安装IDEA软件 解压安装包&#xff0c;找到对应的idea可执行文件&#xff0c;右键选择以管理员身份运行&#xff0c;执行安装操作 3、运行之后&#xff0c;点击NEXT&#xff0c;进入下一步 4、…

RISC-V特权架构 - 特权模式与指令

RV32/64 特权架构 - 特权模式与指令 1 特权模式2 特权指令2.1 mret&#xff08;从机器模式返回到先前的模式&#xff09;2.2 sret&#xff08;从监管模式返回到先前的模式&#xff09;2.3 wfi&#xff08;等待中断&#xff09;2.4 sfence.vma&#xff08;内存屏障&#xff09; …

官宣 | 凯琦供应链成为亚马逊SPN物流服务商!

再播一条喜讯&#xff01;在亚马逊官方平台的筛选考核下&#xff0c;凯琦供应链近日正式入驻亚马逊SPN服务商平台&#xff0c;成为亚马逊SPN第三方承运商。 这也标志着凯琦9年来在FBA物流领域的服务质量得到了客户、官方及行业的广泛认可&#xff0c;未来凯琦将继续为亚马逊卖家…

【LeetCode题解】2182. 构造限制重复的字符串+82. 删除排序链表中的重复元素 II+83. 删除排序链表中的重复元素

文章目录 [2182. 构造限制重复的字符串](https://leetcode.cn/problems/construct-string-with-repeat-limit/)思路&#xff1a; [82. 删除排序链表中的重复元素 II](https://leetcode.cn/problems/remove-duplicates-from-sorted-list-ii/)[83. 删除排序链表中的重复元素](htt…

swoole

php是单线程。php是靠多进程来处理任务&#xff0c;任何后端语言都可以采用多进程处理方式。如我们常用的php-fpm进程管理器。线程与协程,大小的关系是进程>线程>协程,而我们所说的swoole让php实现了多线程,其实在这里来说,就是好比让php创建了多个进程,每个进程执行一条…

前端学习第六天-css浮动和定位

达标要求 了解浮动的意义 掌握浮动的样式属性 熟练应用清除浮动 熟练掌握定位的三种方式 能够说出网页布局的不同方式的意义 1. 浮动(float) 1.1 CSS 布局的三种机制 网页布局的核心——就是用 CSS 来摆放盒子。CSS 提供了 3 种机制来设置盒子的摆放位置&#xff0c;分…

基于原子变量的内存模型优化

概述 线程间同步通常的实现方法通常为互斥锁&#xff0c;但互斥锁对性能造成了影响&#xff0c;C11引入了内存模型&#xff0c;定义了STD::memory_order枚举&#xff0c;结合原子性操作&#xff0c;实现无锁线程数据同步。 关于memory_order memory_order_relaxed&#xff1…