蓝桥备考--必考题型--广度优先搜索bfs
蓝桥杯近几年基本上都会出一道广度优先搜索题型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
迷宫
题意:给定一个n*m的二维整数数组,用来表示一个迷宫,数组中只包含.或#,其中.表示 可以走的路,#表示不可通过的墙壁。 最初,有一个人位于左上角(0,0)处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。 请问,该人从左上角移动至右下角处,至少需要移动多少次。
数据保证(0,0)处和(n-1,m-1)处的数字为0,且一定至少存在一条通路。
输入格式
第一行包含两个整数n和m。
接下来n行,每行包含m(.或#),表示完整的二维数组迷宫。
输出格式
输出一个整数,表示从左上角移动至右下角的最少移动次数。
数据范围
1≤n,m≤100
输入样例:
5 5
. . # # #
# . . . .
# . # . #
# . # . #
# . # . .
输出样例:
9
代码1
#include<bits/stdc++.h>
using namespace std;
int n,m;
char a[100][100];
struct Point
{
int x, y, step;
};
queue<Point> q;//队列
bool vis[100][100];//0或1标识
int dir[4][2] = { {1,0},{0,1},{-1,0},{0,-1} };
int bfs()
{
while (1)
{
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 && a[x1][y1] == '.' && vis[x1][y1] == 0)
{
if (x1 == n - 1 && y1 == m - 1)
{
return q1.step + 1;
}
q.push(Point{ x1,y1,q1.step + 1 });
vis[x1][y1] = 1;
}
}
}
}
int main()
{
cin >> n >> m;
for (int i = 0; i < n; i++)
{
for (int j = 0; j<m;j++)
{
cin >> a[i][j];
}
}
q.push(Point{0,0,1});
vis[0][0] = 1;
cout << bfs();
return 0;
}
题目2
数水坑
题目描述
由于近期的降雨,农民约翰的田地里的许多地方都积水了,用一个N×M(1<=N<=100; 1<=M<=100)的网格图表示。每个网格中有水(“W”)或是旱地(“.”)。一个网格与周围的 八个网格相连,而一组相连的网格视为一个水坑。农夫约翰想知道他的地里形成了多少个水 坑。给出一张农夫约翰的田地图,确定当中有多少个水坑。
输入
第一行:两个空格隔开的整数:N和M 第二行到第N+1行:每行M个字符,每个字符是‘W’或‘.’,它们表示网格图中的一排。字符之间没有空格。
输出
一行:水坑的数量
样例输入
W........WW.
.WWW.....WWW
....WW...WW.
.........WW.
.........W..
..W......W..
.W.W.....WW.
W.W.W.....W.
.W.W......W.
..W.......W.
样例输出
3
这道题注意一下是8个方向移动!
代码2
#include<bits/stdc++.h>
using namespace std;
int n, m;
char a[100][100];
struct Point
{
int x, y;
};
queue<Point> q;
bool vis[100][100] ;
int dir[8][2] = { {1,0},{0,1},{-1,0},{0,-1},{-1,-1},{1,1},{-1,1},{1,-1} };
void bfs()
{
while (!q.empty())
{
Point q1 = q.front();
q.pop();
for (int i = 0; i < 8; i++)
{
int x1 = q1.x + dir[i][0];
int y1 = q1.y + dir[i][1];
if (x1 >= 0 && x1 < n && y1 >= 0 && y1 < m && a[x1][y1] == 'W' && vis[x1][y1] == 0)
{
q.push(Point{ x1,y1 });
vis[x1][y1] = 1;
}
}
}
}
int main()
{
cin >> n >> m;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
cin >> a[i][j];
}
}
int ans=0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (a[i][j] == 'W' && vis[i][j] == 0)
{
q.push(Point{ i,j });
vis[i][j] = 1;
bfs();
ans++;
}
}
}
cout << ans;
return 0;
}
题目3
拐弯
题目描述
给出一张地图,这张地图被分为n×m(n,m<=100) 个方块,任何一个方块不是平地就是高山。平地可以通过,高山则不能。现在你处在地图的 (x1,y1)这块平地,问:你至少需要拐几个弯才能到达目的地(x 2,y2)?你只能沿着水平和垂直方向的平地上行进,拐弯次数就等于行进方向的改变(从水平到垂直或从垂直到水平)的次数。
输入
第1行:n∗ m
第2至n+1行:整个地图地形描述(0:空地;1: 高山)
第n +2行:x1y1x2y2(分别为起点、终点坐标)
输出
s(即最少的拐弯次数)
样例输入
5 7
1 0 0 0 0 1 0
0 0 1 0 1 0 0
0 0 0 0 1 0 1
0 1 1 0 0 0 0
0 0 0 0 1 1 0
1 3 1 7
样例输出
5
注意边界!注意是最少!注意第一步走不算拐弯,需要减去!
代码3
#include<bits/stdc++.h>
using namespace std;
int n, m;
int a[100][100];
struct Point
{
int x, y, lastdir, guai;//坐标、上次拐的方向、拐的次数
};
queue<Point> q;
int dir[4][2] = { {1,0},{0,1},{-1,0},{0,-1} };
int vis[100][100] = { 0 };
int x, y, x2, y2;
int min_guai = INT_MAX;
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 && a[x1][y1] != 1 && vis[x1][y1] == 0)
{
if (x1 == x2 && y1 == y2)//终点
{
if (q1.lastdir != i)//拐弯记录
{
q1.guai++;
q1.lastdir = i;
}
min_guai=min(q1.guai,min_guai);
break;
}
else
{
if (q1.lastdir != i)//拐弯记录
{
q1.guai++;
}
q.push(Point{ x1,y1,i,q1.guai });
}
vis[x1][y1] = 1;
}
}
}
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> a[i][j];
}
}
cin >> x >> y >> x2 >> y2;
Point q0{ x,y,4,0 };
vis[x][y] = 1;
q.push(q0);
bfs();
cout << min_guai-1 << endl;//起步记录了1次,结果减去
return 0;
}
少年没有乌托邦,心向远方自明朗!
如果这个博客对你有帮助,给博主一个免费的点赞就是最大的帮助❤
欢迎各位点赞,收藏和关注哦❤
如果有疑问或有不同见解,欢迎在评论区留言❤
后续会继续更新大连理工大学相关课程和有关蓝桥杯的内容和示例
点赞加关注,学习不迷路,好,本次的学习就到这里啦!!!
ok,我们下次再见!