bfs超!超!超!详细步骤梳理!!!

简介

我个人理解的是
bfs就是自当前一点,逐渐地向外扩张,有种水漫金山的感觉。
也可以说是枚举每一个正确点的”未来的“可能性。
例如:
在第一个二维的地图中,题目要求我们从起点开始搜索终点的位置。
1.将起点放入队列;
2.取出队列中的第一个数(当前取出的是起点),看其邻近的点是否符合要求,若符合,则将其放入队列;
3.将队列中的点依次取出,对于每一个点,都重复2的步骤;
4.判断当前点是否为终点;

以上只是一个大致的步骤,在不同的题目中,可能需要做出相应的修改。同时,bfs的模板可能在一些小的方面会有不同的地方(但其实差不多)。

一、bfs代码分块解析

1.定义需要的各种东西

以下使用的是队列,若题目中涉及到某个点在遇到什么东西时(比如怪物),会原地停留一段时间,这时就要用优先队列来使最终的答案为最优。
使用优先队列需对”<"(小于符号)进行重载。
此处的maze中,1为墙壁,0为路,2为终点。

char maze[250][250];//此处为地图,根据题目要求会有所不同
int vis[250][250];//用来标记已经走过的点,部分题目可以通过直接改变地图中的信息发挥同样的作用
int n,m;//地图大小
struct node
{
	 int x,y,step;//横坐标,纵坐标,步数
};
queue<node> q;//用来存放下一步的点
node now,next;//当前的情况,下一步的情况
int a[4]={0,0,1,-1},b[4]={1,-1,0,0};//此处为每一个点需要走的4个方向

2.写出bfs函数

  • 首先把大致框架写出
    此处的bfs()中的括号可以根据题目要求将需要的数据代入(例如起点的坐标,终点的坐标),这里也可以写成 bfs(int x,int y) 等等,但没必要,也可根据需要使用bool来定义bfs函数,
int bfs()
{
}
  • 接着,为了防止在多组输入的题目中发生队列不为空,标记点未初始化等错误,需要清除原来的标记清空队列
int bfs()
{
	while(!q.empty())
	q.pop();
	memset(vis,0,sizeof(vis));
}
  • 然后,将起点入队,这里假设起点是(0,0)。
int bfs()
{
	while(!q.empty())
	q.pop();
	memset(vis,0,sizeof(vis));
	//—————————————————————————————步骤分界线1
	now.x=0;
	now.y=0;
	now.step=0;//now是当前选择的点
	q.push(now);//放入队列中
}
  • 然后是取出队列顶端(步数最优)的那个点,同时移除将其移除。
int bfs()
{
	while(!q.empty())
	q.pop();
	memset(vis,0,sizeof(vis));
	//————————————————————————————步骤分界线1
	now.x=0;
	now.y=0;
	now.step=0;//now是当前选择的点
	q.push(now);//放入队列中
	//————————————————————————————步骤分界线2
	now=q.front();//now表示当前选择的点
	q.pop();
}
  • 然后当前选择的点(now)进行四个方向的操作。
int bfs()
{
   while(!q.empty())
   q.pop();
   memset(vis,0,sizeof(vis));
   //————————————————————————————步骤分界线1
   now.x=0;
   now.y=0;
   now.step=0;//now是当前选择的点
   q.push(now);//放入队列中
   //————————————————————————————步骤分界线2
   now=q.front();//now表示当前选择的点
   q.pop();
   //————————————————————————————步骤分界线3
   for(int i=0;i<4;i++)
   {
   		next.x=now.x+a[i];
   		next.y=now.y+b[i];
   		next.step=now.step+1;
   }
}
  • 在每次操作后(也就是每当for循环一次后),需要判断这个点是否符合要求(比如说看这个点有没有超出地图边界,是不是已经走过了)
int bfs()
{
   while(!q.empty())
   q.pop();
   memset(vis,0,sizeof(vis));
   //————————————————————————————步骤分界线1
   now.x=0;
   now.y=0;
   now.step=0;//now是当前选择的点
   q.push(now);//放入队列中
   //————————————————————————————步骤分界线2
   now=q.top();//now表示当前选择的点
   q.pop();
   //————————————————————————————步骤分界线3
   for(int i=0;i<4;i++)
   {
   		next.x=now.x+a[i];
   		next.y=now.y+b[i];
   		next.step=now.step+1;
   //————————————————————————————步骤分界线4
   		if(next.x>=0&&next.x<m&&next.y>=0&&next.y<n&&vis[next.x][next.y]==0&&maze[next.x][next.y]==0)//判断这个点是否符合要求
   		{
   				vis[next.x][next.y]=1;
   				q.push(next);
   		}
   }
}
  • 最后是判断是否走到了终点(这里有很多种判断方式,我们可以在取出队列中的一个点时进行判断,也可以在对当前点进行操作后判断操作点是否为终点等等,这里为了让步骤好看一点,使用第二种方式判断)。
int bfs()
{
  while(!q.empty())
  q.pop();
  memset(vis,0,sizeof(vis));
  //————————————————————————————步骤分界线1
  now.x=0;
  now.y=0;
  now.step=0;//now是当前选择的点
  q.push(now);//放入队列中
  //————————————————————————————步骤分界线2
  now=q.front();//now表示当前选择的点
  q.pop();
  //————————————————————————————步骤分界线3
  for(int i=0;i<4;i++)
  {
  		next.x=now.x+a[i];
  		next.y=now.y+b[i];
  		next.step=now.step+1;
  }
}
  • 在每次操作后(也就是每当for循环一次后),需要判断这个点是否符合要求(比如说看这个点有没有超出地图边界,是不是已经走过了)
int bfs()
{
   while(!q.empty())
   q.pop();
   memset(vis,0,sizeof(vis));
   //————————————————————————————步骤分界线1
   now.x=0;
   now.y=0;
   now.step=0;//now是当前选择的点
   q.push(now);//放入队列中
   //————————————————————————————步骤分界线2
   now=q.top();//now表示当前选择的点
   q.pop();
   //————————————————————————————步骤分界线3
   for(int i=0;i<4;i++)
   {
   		next.x=now.x+a[i];
   		next.y=now.y+b[i];
   		next.step=now.step+1;
   //————————————————————————————步骤分界线4
   		if(next.x>=0&&next.x<m&&next.y>=0&&next.y<n&&vis[next.x][next.y]==0&&maze[next.x][next.y]==0)//判断这个点是否符合要求
   		{
   				vis[next.x][next.y]=1;
   				q.push(next);
   //————————————————————————————步骤分界线5
   				if(maze[next.x][next.y]==2)
   				{
   					return next.step;
   				}
   		}
   }
}

结尾

以上是bfs的一般写法,根据题目要求做出更改,重在理解。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值