【教程】BFS学习笔记

By weizexin \text{weizexin} weizexin

  • 例子(已被授予主人公的名字使用权)

ZZJ 进入了一个 n × m 的迷宫矩阵,可执着的他表示要穿过迷宫。

ZZJ 在地图的左上角,而迷宫出口在右下角,设进入每个房间都需要 1 的时间,他在入口的地面上捡到一张迷宫地图,发现有一些障碍物(图中以“障碍”表示,代码中以“#”表示,存在map数组中),于是他决定计算出自己到终点最少需要时间(请思考后再往下看)。

迷宫图片

  • 思路:

  • 首先,我们需要一个小本本存ZZJ到达的地方及步数:

struct nod{int x,y,t;}f[100001];//x,y表示位置,t表示ZZJ到达此点需要的步数
  • 其次,我们需要一个bool数组存i,j这个位置是否被走过以及一个map数组存地图:
bool bz[101][101];//这里以0<n,m<=100为数据范围,实际情况请以题面修改数组范围 char map[101][101]; 
  • 再次,我们需要一个方向数组,使ZZJ能上、下、左、右移动:
int dx[4]={0,1,0,-1}; int dy[4]={1,0,-1,0}; 
  • 准备完毕了,ZZJ可以出发啦!
  • 首先,ZZJ将自己的位置存进小本本的第一格里:
tou=1,wei=2;//用两个指针指向小本本队头和队尾 f[tou].x=1; f[tou].y=1; f[tou].t=0;
  • 接着,ZZJ通过方向数组到达一个新位置:
int nx=f[tou].x+dx[i]; int ny=f[tou].y+dy[i];
  • 但是ZZJ有可能跑出了迷宫,掉下悬崖了,所以我们要判断一下ZZJ站在的位置是否在迷宫内:
if(nx<1||nx>n||ny<1||ny>m)continue;//跑出去就不要他了
  • 如果ZZJ已经到了终点,那就是最短到达的距离啦(因为在这个地图中到达每一个点距离都为1),输出小本本的当前的 t + 1 t+1 t+1 ,退出搜索就好啦就好啦:
if(nx==n&&ny==m) 
{
	printf("ZZJ到达终点的最短距离是:%d",f[tou].t+1);
	return;
} 
  • 如果ZZJ到达的是一个新的非障碍的点,并且没来过,ZZJ就在他的小本本上记录下他的位置:
if(map[nx][ny]=='.'&&bz[nx][ny]==false)
{
	bz[nx][ny]=true;
	f[wei].x=nx;
	f[wei].y=ny;
	f[wei].t=f[tou].t+1;
	wei++;
}
  • ZZJ走过了(遍历)周围可走的点后,就将小本本的队头往后挪一个,开始了新的遍历(直到没有点可以更新出新的点时停止,即 t o u = w e i tou=wei tou=wei ):
tou++;
  • 这就是整个bfs的完整过程啦,上完整代码:
#include<cstdio>
int n,m,tou,wei;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
bool bz[101][101];
char map[101][102];
struct nod{int x,y,t;} f[10001];
void bfs(int sx,int sy)
{
	tou=1,wei=2;
	f[tou].x=sx;
	f[tou].y=sy;
	f[tou].t=0;
	while(tou<wei)
	{
		for(int i=0;i<3;i++)
		{
			int nx=f[tou].x+dx[i];
			int ny=f[tou].y+dy[i];
			if(nx<1 || nx>n || ny<1 || ny>m)
				continue;
			if(nx==n && ny==m)
			{
				printf("ZZJ到达终点的最短距离是:%d",f[tou].t+1);
				return;
			}
			if(map[nx][ny]=='.'&&bz[nx][ny]==false)
			{
				bz[nx][ny]=true;
				f[wei].x=nx;
				f[wei].y=ny;
				f[wei].t=f[tou].t+1;
				wei++;
			}
		}
		tou++;
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m+1;j++)
		{
			scanf("%c",&map[i][j]);//结尾要多读一个换行符
		}
	}
	bfs(1,1);
	return 0;
}
  • 如果理解透了这道题,就练练手吧:

  • 题目练习

  • 鸣谢: @ zhongzijun \text{zhongzijun} zhongzijun

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值