简介
我个人理解的是
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的一般写法,根据题目要求做出更改,重在理解。