17-BFS(广度优先搜索算法)

文章介绍了BFS(广度优先搜索)算法,主要用于解决权重相同图的最短路径问题。通过一个迷宫问题的例子,详细阐述了BFS如何一层一层地搜索,找到从入口到出口的最短距离。算法中涉及棋盘布局、距离数组、移动方向和队列模拟,最终找到右下角出口的距离。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 BFS广度优先搜索算法,是最简便的图搜索算法,常用于解决权重相同且不变的图的最短路求解问题。

广度优先算法(BFS)

BFS广度优先搜索算法),不同于DFS一搜就一直找到叶节点,它的搜索逻辑是一层一层地搜节点,直至找到所需的数据。相较于DFS,BFS占据的空间更大,但是它还是有好处的,我们常用的最短路算法就来源于BFS。

 

下面还是以常见的例子来说明BFS广度搜索算法的应用场景。

迷宫问题

假设我们有下面一个这样的迷宫,它的入口在左上方,出口在右下方,o是可以走的格子、x是不可以走的障碍物,现在我们的任务是要找出从入口到出口所需走到最短距离。

我们可以看到,从入口到出口有很多条路径,但是每两个点之间距离都是1(权重相等),但是红色路径是距离最短的, 其它还有类似绿色路径这样的线路:

 

我们可以尝试使用BFS搜索算法:假设入口第一个点是树的根节点,我们BFS搜索每次搜索下一层的节点可以理解为搜索根节点附近符合条件(可以进行单次移动的点)。为了用代码实现上面的操作,我们首先需要制作一个棋盘和一个dist数组,dist数组它的每个元素存储的是棋盘上对应点到入口节点的距离,而l对组数组存储的是每一步当前点的位置:

#include<iostream>

using namespace std;

const int N = 100;
int n, m;
int chessboard[N][N];//棋盘布局
int dist[N][N];//当前点离起点的距离
pair<int, int> l[N];

int main()
{
	cin >> n >> m;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < m; j++)
		{
			cin >> chessboard[i][j];
		}
	}
	return 0;
}

在BFS函数里第一步是先将dist数组初始化,即设置每一个点到入口根节点的距离都是-1,除了根节点本身是0。

	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < m; j++)
			dist[i][j] = -1;
	}

我们知道从一个点移动到另一个点,每种移动总结起来共有四种情况,向上、向下、向左和向右;我们每个点下次移动都是需要进行四部分的移动,只不过将1、不能过的位置(有x阻碍物)2、之前走过的情况都舍去。这里我们将四种操作具体实例化为两个数组move_x和move_y,move_x[0]、move_y[0]表示左移一个单位;move_x[0]、move_y[1]表示右移一个单位;move_x[1]、move_y[0]表示上移一个单位;move_x[1]、move_y[1]表示下移一个单位;

以后我们每次操作,只需要将当前的位置的横坐标和纵坐标加上对应下表的数组元素就可以表示四种移动

	int move_x[4] = {-1,1,0,0};
	int move_y[4] = {0,0,1,-1};

打算将每一步的当前点都放进一个队列里,所以我们还需要模拟一个队列,当然也可以利用STL里的queue。我队列每次取出对应着我们棋盘上面的的一次移动,这里我们新开一个对组,它存储的是当前移动到的位置now_loct,然后将l数组里面的当前元素赋予给这个对组,再将l数组的队头加加,准备接收下一个新位置。

然后这个for循环就是将四次操作都试一遍,并且每次新的位置都放到另一个新的队组new——loct中。不过只有满足六个条件的新位置才算合适的,才能被放进队列中。六个条件分别是:

1、新的x位置不能越过左边界

2、新的y也不能低于下边界

3、新的x位置不能超过右边界

4、新的y不能高过上边界

5、新的位置必须是棋盘上可走的点

6、新的位置不能是之前走过的

当满足这些条件的新位置才算有效的,于是更新新位置到旧位置之间走过的总距离,并且将新位置放入队列。

while (hh <= tt)
	{
		pair<int, int> now_loct= l[hh++];
		//移动
		for (int p = 0; p < 4; p++)
		{
			pair<int, int>new_loct;
			new_loct.first = now_loct.first + move_x[p];
			new_loct.second = now_loct.second + move_y[p];
			if (new_loct.first >= 0 && new_loct.second >= 0 &&
				new_loct.first < n && new_loct.second < m &&
				chessboard[new_loct.first][new_loct.second] == 0 &&
				dist[new_loct.first][new_loct.second] == -1
				)
			{
				dist[new_loct.first][new_loct.second] = dist[now_loct.first]        [now_loct.second] + 1;
				l[++tt] = { new_loct.first,new_loct.second };
			}
		}
	}

最后返回右下角点(出点)的距离即可。

return dist[n-1][m-1];

所以总的代码如下:

#include<iostream>

using namespace std;

const int N = 100;
int n, m;
int chessboard[N][N];//棋盘布局
int dist[N][N];//当前点离起点的距离
pair<int, int> l[N];

int BFS()
{
	int hh=0, tt = 0;
	l[0] = { 0,0 };
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < m; j++)
			dist[i][j] = -1;
	}
	dist[0][0] = 0;
	int move_x[4] = {-1,1,0,0};
	int move_y[4] = {0,0,1,-1};
	//模拟队列
	while (hh <= tt)
	{
		pair<int, int> now_loct= l[hh++];
		//移动
		for (int p = 0; p < 4; p++)
		{
			pair<int, int>new_loct;
			new_loct.first = now_loct.first + move_x[p];
			new_loct.second = now_loct.second + move_y[p];
			if (new_loct.first >= 0 && new_loct.second >= 0 &&
				new_loct.first < n && new_loct.second < m &&
				chessboard[new_loct.first][new_loct.second] == 0 &&
				dist[new_loct.first][new_loct.second] == -1
				)
			{
				dist[new_loct.first][new_loct.second] = dist[now_loct.first][now_loct.second] + 1;
				l[++tt] = { new_loct.first,new_loct.second };
			}
		}
	}
	return dist[n-1][m-1];
}

int main()
{
	cin >> n >> m;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < m; j++)
		{
			cin >> chessboard[i][j];
		}
	}
	cout<<BFS();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值