蓝桥杯算法竞赛备考(一)—— 搜索专题(下)(C++)

本文介绍了蓝桥杯算法竞赛中搜索专题的下篇,重点讲解了广度优先搜索(BFS)的概念、用队列实现BFS的模板,以及BFS的经典例题,包括迷宫最短路径、马的遍历和连通块问题。文章还简要提及了记忆化搜索在斐波那契数列中的应用。
摘要由CSDN通过智能技术生成

在这里插入图片描述

写在前面

hello小伙伴们,我们又见面啦~上一篇文章蓝桥杯算法竞赛备考(一)—— 搜索专题(上)(C++)得到了小伙伴们的认可,我真的是喜出望外,小伙伴们的支持是我最大的动力噢~
好啦废话不多说,让我们进入今天的算法学习吧~
在这里插入图片描述
今天讲的主要有以下几点内容噢!

  1. 广度优先搜索的基本思想
  2. BFS的模板
  3. BFS经典例题
  4. 记忆化搜索


一、广度优先搜索(BFS)

深度优先搜索会优先考虑搜索的深度,就是找不到答案不回头。 当答案在解答树中比较稀疏的时候,DFS会陷入过深的情况,搜索很多无效状态,一时半会找不到解,这时候我们就可以用BFS啦~在连通性,最短路问题中常优先考虑BFS

BFSDFS搜索的顺序是不一样的。DFS前面已经讲到过,是以深度为第一关键词的,也就是说从某个结点出发总是先选择其中一个分支前进,而不管其他的分支,直到碰到死胡同才停止。然后回溯到上一个结点选择其他的分支。
BFS搜索的顺序是这样的,从某个结点出发,总是先依次访问这个结点能直接到达的所有结点,然后再访问这些结点所能直接到达的所有结点,依次类推,直到所有的结点都访问完毕。
下面呢我们看一个迷宫,小伙伴们可能会对BFS有一个清晰的认识。
在这里插入图片描述
BFS搜索的顺序是这个样子滴~首先从起点A出发,它能到达的所有结点有BC(第二层),因此接下来去访问BB能直接到达DE(第三层),接下来访问CC能直接到达FG(第三层)。第二层访问结束,接下来访问DD能直接到达IGH(第四层)。接下来访问EE能直接到达MLK(第四层),接着访问FF是死胡同。接下来访问GG是终点,搜索结束。

至于那些未访问过的结点,我们就不用去管它了。

可以看出层数就是从结点A出发到达其他结点的最小步数。广度优先搜索会优先考虑每种状一个专题态的和初始状态的距离,也就是与初始状态越接近的就会越先考虑。这就能保证一个状态被访问时一定是采用的最短路径。

其实DFS和BFS都可以从树的角度去分析。
在这里插入图片描述
DFS相当于树的先序遍历,BFS相当于树的层次遍历。
DFS搜索顺序是123456BFS搜索顺序是125346
相信小伙伴们很容易就能看出来~


二、用队列来实现BFS(模板)

BFS的搜索过程很像一个队列,队列的特点就是先进先出。谁入队早就先访问谁。
我们简单的来分析一下队列模拟的过程~

  • 先把起点A入队,取出队首A,将A直接到达的BC入队。队列元素有{ BC}。
  • 再将队首B取出,将B直接到达的DE入队。此时队列元素有{ CDE}。
  • 再将队首C出队,将C直接到达的FG入队。此时队列元素有{ DEFG}。
  • 再将队首D出队,将D直接到达的IJH入队。此时队列元素有{ EFGIJH}。
  • 再将队首E出队,将E直接到达的MLK入队。此时队列元素有{ FGIJHMLK
  • 再将队首F出队,F没有直接相连的新节点,此时队列元素有{ GIJHMLK}。
  • 再将G出队,找到终点,算法结束。

下面给出BFS的模板。

还是那句话多记些模板对比赛是很有帮助的噢~

void bfs()
{
   
	queue<int> q;//一般用stl库中的queue来实现队列比较方便
	q.push(起点S);//将初始状态入队
	标记初始状态已入队。
	while(!q.empty())//队列不为空就执行入队出队操作
	{
   
		top = q.front();//取出队首
		q.pop();//队首出队
		for (枚举所有可扩展的状态)
		{
   
			if (check())//状态合法
			{
   
				q.push(temp);//状态入队
				标记成已入队。
			}
			
		}
	}

对模板做几点说明

  1. 建议大家用stl中的queue表示队列。操作方便。头文件要加#include<queue>
  2. 要区分front()pop()的区别,front的返回值是队首元素,而pop没有返回值。
  3. 我们常用一个新变量来储存队首元素,以便在它出队后方便下面的操作。
    top = q.front()

还有一个问题,我们在使用BFS时会设一个inq数组记录结点有没有入队,为什么不是记录结点有没有访问呢,不知道小伙伴们想没想过这个问题。
区别在于,设置成结点是否已访问,会导致有些点在队列中但是还没有被访问,由于其他结点可以到达它而将这个结点入队,导致很多结点重复入队,这是很不明智的。

以后也会专门出一篇讲解比赛中常用的STL标准模板库。
上面对BFS的讲解参考胡凡《算法笔记》并补充了自己对BFS的理解。


三、BFS经典例题

1. 模板题——迷宫最短路

在这里插入图片描述
在这里插入图片描述
题目分析
该题是要求从起点到终点的最小步数。我们可以有两种解决方案,DFSBFS

  • 可以DFS所有从起点到终点的所有路径,然后取路径最短的那条。
  • BFS是很理所当然的,因为求的是最小步数,涉及最短问题

我们先来看一下BFS该如何解决这个问题。因为是板子题嘛直接照着模板敲就好了~

AC代码(BFS)

//bfs 广度优先搜索
//迷宫问题 求解最短路径
#include <iostream>
#include <queue>

using namespace std;

const int N = 100;
int n, m;//n行m列
char maze[N][N];//迷宫
bool inq[N][N];//记录位置(x,y)是否入队
int x[4] = {
   -1, 1, 0, 0};//增量数组
int y[4] = {
   0, 0, -1, 1};

struct node
{
   
    int x, y;
    int step;
}s, t, Node;//s起点 t终点 Node临时节点

bool test(int x, int y)//判断位置(x,y)是否有效
{
    //以下三种情况不能入队
    if (x >= n || x < 0 || y >= m || y < 0) return false;//出界
    if (maze[x][y] == '*') return false;//墙壁
    if (inq[x][y] == true) return false;//已入队
    return true;//其余情况可以将该点入队
}

int bfs()
{
   
    queue<node> q;//定义队列
    q.push(s);//将起点入队
    while(!q.empty())//队列不为空执行
    {
   
        node top = q.front();//取出队首元素
        q.pop();//出队
        //inq[s.x][s.y] = true;//将起点设为已入队
        if (top.x == t.x && top.y == t.y)//到达终点
        {
   
            return top.step;返回终点的层数,即最少步数
        
评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值