蓝桥杯备考--必考题型--广度优先搜索bfs plus

蓝桥杯近几年基本上都会出一道广度优先搜索题型bfs

广度优先搜索

BFS(广度优先搜索,Breadth-FirstSearch)是一种用于遍历或搜索树或图的算法。它从根节点(或任意节点)开始,逐层访问邻近节点,直到找到目标或遍历完所有节点。

BFS的基本步骤:

  • 1.初始化队列:将起始节点放入队列。
  • 2.访问节点:从队列中取出一个节点并访问。
  • 3.扩展邻近节点:将当前节点的所有未访问邻近节点加入队列。
  • 4.重复:重复步骤2和3,直到队列为空。

BFS的特点: 使用队列:BFS使用队列(FIFO)来管理待访问节点。

逐层遍历:BFS按层扩展,先访问离起始节点最近的节点。

空间复杂度高:在最坏情况下,BFS需要存储所有节点,空间复杂度为O(V),其中V是节点数。

时间复杂度:对于图,时间复杂度为O(V+E),V是节点数,E是边数。

基本做题上都是这个步骤,答案的模版比较固定,就是有一些题会有一些小细节需要注意

下面是几道进阶的题目,比较基础的题目看我之前的博客!

进阶题目1

玉米迷宫        

        去年秋天,农夫约翰带着奶牛参观了一个玉米迷宫。但这不是普通的玉米迷宫:它有几个重 力驱动的传送滑梯,可以让奶牛从迷宫中的一个点瞬间传送到另一个点。滑梯是双向工作的: 一头牛可以从滑梯的起点瞬间滑到终点,或者从终点滑到起点。如果一头牛踩在滑梯两端的 空间上,她必须使用滑梯。玉米迷宫的外面除了一个出口,全是玉米。迷宫可以用一个Nx M(2<=N<=300;2<=M<=300)网格。每个网格元素包含以下项目之一:

奶牛们去一个 N×M 玉米迷宫,2≤N≤300,2≤M≤300。

迷宫里有一些传送装置,可以将奶牛从一点到另一点进行瞬间转移。这些装置可以双向使用。

如果一头奶牛处在这个装置的起点或者终点,这头奶牛就必须使用这个装置。

玉米迷宫除了唯一的一个出口都被玉米包围。

迷宫中的每个元素都由以下项目中的一项组成:

玉米,# 表示,这些格子是不可以通过的。

草地,. 表示,可以简单的通过。

传送装置,每一对大写字母 A 到 Z 表示。

出口,= 表示。

起点, @ 表示 奶牛能在一格草地上可能存在的四个相邻的格子移动,花费 1 个单位时间。从装置的一个 结点到另一个结点不花时间。

贝西迷路了。她知道自己在网格上的位置,并用符号(@)标记了她当前的草地空间。她移 动到出口空间的最短时间是多少?

【输入】

第一行:两个用空格隔开的整数 N 和 M。

第 2∼ N+1 行:第 i+1 行描述了迷宫中的第 i 行的情况(共有M个字符,每个字符中间没 有空格)

【输出】

一个整数,表示起点到出口所需的最短时间。

样例输入

5 6

###=##

#.W.##

#.####

#.@W##

######

样例输出

3

 代码1

#include<bits/stdc++.h>
using namespace std;
int n, m, x2, y2;//大小
char a[400][400];

int dir[4][2] = { {1,0},{0,1},{-1,0},{0,-1} };
int vis[400][400] = { 0 };

struct Point
{
	int x, y, time;
};

int mtime = INT_MAX;
queue<Point> q;

struct chuan //传送门
{
	int inx, iny, outx, outy;
}c[30];

void bfs()
{
	while (!q.empty())
	{
		Point q1 = q.front();
		q.pop();
		for (int i = 0; i < 4; i++)
		{
			int x1 = q1.x + dir[i][0];
			int y1 = q1.y + dir[i][1];
			if (x1 >= 0 && x1 < n && y1 >= 0 && y1 < m && vis[x1][y1] != 1 && a[x1][y1]!='#')
			{
				vis[x1][y1] = 1;
				q1.time++;
				if (a[x1][y1] == '=')//出口
				{
					mtime = min( mtime, q1.time);
				}
				else if ((a[x1][y1] - 'A')>=0&& (a[x1][y1] - 'A')<26)//通道
				{
					if (c[(a[x1][y1] - 'A')].inx == x1)
					{
						q.push(Point{ c[(a[x1][y1] - 'A')].outx , c[(a[x1][y1] - 'A')].outy,q1.time});
					}
					else
					{
						q.push(Point{ c[(a[x1][y1] - 'A')].inx , c[(a[x1][y1] - 'A')].iny,q1.time });
					}
				}
				else// .
				{
					q.push(Point{ x1,y1,q1.time });
				}
			}
		}
	}
}

int main()
{
	cin >> n >> m;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < m; j++)
		{
			cin >> a[i][j];
			if (a[i][j] == '=') x2 = i, y2 = j;//出口
			else if( (a[i][j]-'A')>=0&& (a[i][j] - 'A')<26)//通道
			{
				if (c[(a[i][j] - 'A')].inx == 0)//题中表示,迷宫的外围只有玉米和出口,没有通道,所以仅需判断是否等于0即可
				{
					c[(a[i][j] - 'A')].inx = i;
					c[(a[i][j] - 'A')].iny = j;
				}
				else//第二个通道口
				{
					c[(a[i][j] - 'A')].outx = i;
					c[(a[i][j] - 'A')].outy = j;
				}
			}
			else if (a[i][j] == '@')//起点,压入队列
			{
				q.push(Point{ i, j, 0 });
				vis[i][j] = 1;
			}
		}
	}

	Point out = { x2,y2,0 };
	bfs();
	cout << mtime << endl;
	return 0;
}

进阶题目2

跨越草原

        在一片广阔的土地上,有一个鸟人,他需要从这里穿过原野,回到基地。这片原野上,有平 地(P)、有湖泊(L),因为鸟人可以飞,所以呢,有的时候,他可以飞越湖泊。现在,鸟人需 要用最快的时间,回到基地。 假设原野是一个m*n的矩阵,有两种地形,用P和L表示。鸟人只能停留在平地上。他目 前处在(1,1)这个位置,而目的地是(m,n)。他可以向上下左右四个方向移动,或者飞行。每移动一格需要1个单位时间。而飞行无论飞多远,都只需要1个单位时间。飞行的途中不可以 变方向,也就是说飞行也只能是上下左右四个方向。并且一次飞行最终必须降落在平地上。 当然,受到能量的限制,鸟人不能无限制的飞行,他总共最多可以飞行的距离为D。

Input

第一行是三个整数,m,n,D,三个数都不超过100,下面是一个m*n的矩阵,表示原野

Output

一个整数,为最短时间,如果无法到达,则输出“impossible”

SampleInput

442

PLLP

PPLP

PPPP

PLLP

SampleOutput

5

代码2

#include<bits/stdc++.h>
 using namespace std;
 char a[100][100];
 int n,m,e;
 struct Point{
	 int x,y,step,energy;
 };
 queue<Point>q;//存储当前点的信息
int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
 bool in(int x,int y){
	 return x>=0&&x<n&&y>=0&&y<m;
 }
 bool vis[100][100];//记录点有没有走过

int bfs(){
	while(1)
	{
		 Point q1=q.front();
		 q.pop();
		for(int i=0;i<4;i++)
		{
			int xx=q1.x+dir[i][0];
			int yy=q1.y+dir[i][1];
			if(xx>=0&&xx<n&&yy>=0&&yy<m&&vis[xx][yy]==0)
			{
				 if(xx==n-1&&yy==m-1)
				 {
					 return q1.step+1;
				 }
				 if(a[xx][yy]=='P')
				 {
					 vis[xx][yy] = 1;
					 q.push(Point{ xx,yy,q1.step + 1,q1.energy });
				 }
				else 
				{
					if (q1.energy > 0) 
					{
						 int xx1 = xx, yy1 = yy;//把起始点存起来
						 while (in(xx, yy) == 1) {//只要在界内就一直进行
						 xx += dir[i][0];
						 yy += dir[i][1];
						 if (xx >= 0 && xx < n && yy >= 0 && yy < m && vis[xx][yy] == 0 && a[xx][yy] == 'P') 
						 {
							 if (abs(xx - xx1) + abs(yy - yy1) < q1.energy) 
							 {
								 q.push(Point{ xx,yy,q1.step + 1,q1.energy - (abs(xx - xx1) + abs(yy - yy1) + 1) });
								 vis[xx][yy] = 1;
							 }
							 else {
								 break;
								 }
							 }
						 }
					 }
				}
			 }
		 }
	}
}
int main() {
	cin >> n >> m >> e;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			cin >> a[i][j];
		}
	}
	vis[0][0] = 1;
	q.push(Point{ 0,0,0,e });
	cout << bfs();
}

进阶题目3

骑士城堡

        贝茜遇到了一件很麻烦的事:她无意中闯入了森林里的一座城堡,如果她想回家,就必须穿 过这片由骑士们守护着的森林.为了能安全地离开,贝茜不得不按照骑士们的要求,在森林 寻找一种特殊的灌木并带一棵给他们.当然,贝茜想早点离开这可怕的森林,于是她必须尽 快完成骑士们给的任务,贝茜随身带着这片森林的地图,地图上的森林被放入了直角坐标系, 并按x,y轴上的单位长度划分成了W×H(1≤W,H≤1000)块,贝茜在地图上查出了她自己以及骑 士们所在的位置,当然地图上也标注了她所需要的灌木生长的区域.某些区域是不能通过的 (比如说沼泽地,悬崖,以及食人兔的聚居地).在没有找到灌木之前,贝茜不能通过骑士 们所在的那个区域,为了确保她自己不会迷路,贝茜只向正北、正东、正南、正西四个方向 移动(注意,她不会走对角线).她要走整整一天,才能从某块区域走到与它相邻的那块区 域. 输入数据保证贝茜一定能完成骑士的任务.贝茜希望你能帮她计算一下,她最少需要多少天才可脱离这可怕的地方?

Input

第1行输入2个用空格隔开的整数,即题目中提到的W、H.

接下来输入贝茜持有的地图,每一行用若干个数字代表地图上对应行的地形.

地图上的数字所对应的地形:

0:贝茜可以通过的空地

1:由于各种原因而不可通行的区域

2:贝茜现在所在的位置

3:骑士们的位置

4:长着贝茜需要的灌木的土地

Output

输出一个正整数D,即贝茜最少要花多少天才能完成骑士们给的任务.

Sample Input(记得有空格)

8 4

41000010

00010100

02113040

00041110

Sample Output

11

代码3

#include<bits/stdc++.h>
using namespace std;
int n, m, sx, sy, ex, ey;
int a[100][100];
bool vis[100][100];
struct Point {
	int x, y, step;
};
int dir[4][2] = { {1,0},{0,1},{-1,0},{0,-1} };
queue<Point> q;
struct guanmu {
	int x, y, step;
}g[100];
int ans = 0;
int bfs() {
	while (q.size() > 0) {
		Point q1 = q.front();
		q.pop();
		for (int i = 0; i < 4; i++) {
			int xx = q1.x + dir[i][0];
			int yy = q1.y + dir[i][1];
			if (xx >= 0 && xx < n && yy >= 0 && yy < m && vis[xx][yy] == 0 && a[xx][yy] != 1) {
				if (a[xx][yy] == 4) {
					g[ans].x = xx;
					g[ans].y = yy;
					g[ans].step = q1.step + 1;
					ans++;
					vis[xx][yy] = 1;
				}
				else {
					q.push(Point{ xx,yy,q1.step + 1 });
					vis[xx][yy] = 1;
				}
			}
		}
	}
	return-1;
}
int bfs1() {
	while (q.size() > 0) {
		Point q1 = q.front();
		q.pop();
		for (int i = 0; i < 4; i++) {
			int xx = q1.x + dir[i][0];
			int yy = q1.y + dir[i][1];
			if (xx >= 0 && xx < n && yy >= 0 && yy < m && vis[xx][yy] == 0 && a[xx][yy] != 1) {
				if (a[xx][yy] == 3) {
					return q1.step + 1;
				}
				else {
					q.push(Point{ xx,yy,q1.step + 1 });
					vis[xx][yy] = 1;
				}
			}
		}
	}
	return-1;
}
int main() {
	cin >> n >> m;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			cin >> a[i][j];
			if (a[i][j] == 2) {
				sx = i;
				sy = j;
			}
		}
	}
	vis[sx][sy] = 1;
	q.push(Point{ sx,sy,0 });
	bfs();//寻找灌木
	int min_step = 10000;
	for (int i = 0; i < ans; i++) {
		memset(vis, 0, sizeof(vis));//每次都要清零,因为从每个灌木丛搜索互不相干
		vis[g[i].x][g[i].y] = 1;
		q.push(Point{ g[i].x,g[i].y,g[i].step });
		min_step = min(min_step, bfs1());
	}
	cout << min_step;
}

少年没有乌托邦,心向远方自明朗!

如果这个博客对你有帮助,给博主一个免费的点赞就是最大的帮助
欢迎各位点赞,收藏关注
如果有疑问或有不同见解,欢迎在评论区留言
后续会继续更新大连理工大学相关课程和有关蓝桥杯的内容和示例
点赞加关注,学习不迷路,好,本次的学习就到这里啦!!!

ok,我们下次再见!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

头发尚存的猿小二

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值