一、定义
从起始节点开始,首先访问所有与起始节点距离为 1 的邻居节点,然后依次访问距离为 2、距离为 3...... 的节点,直到遍历完整个图或找到目标节点为止。
二、核心原理
BFS 算法通常依赖**队列(Queue)**这一数据结构来维护待访问节点的顺序。
使用bfs算法处理的不管是图、树,还是迷宫问题,本质都是"队列+访问标记"的组合,
- 初始化:创建一个队列,将「起始节点」加入队列,并标记该节点为"已访问";
- 循环: 只要队列不为空,就执行以下操作:
- **出队:**取出队列头部的节点(当前节点);
- **处理:**对当前节点进行需要的操作(比如记录路径、判断是否是目标节点);
- **入队:**找到当前节点的所有"未访问"的邻居节点,标记为"已访问",并依次加入队列;
- **终止:**当队列为空,或者找到目标节点时,遍历结束。
三、例题
走迷宫
题目描述(来源于AcWing)
思路
-
用二维数组
g[N][N]存迷宫地图(0 能走,1 是墙),dist[N][N]存每个点到起点的距离,用队列queue<PII>存待遍历的坐标,用方向数组dx[]、dy[]控制上下左右移动。 -
初始化
-
把所有点的距离初始化为
-1(表示没走过) -
起点
(1,1)入队 -
起点距离设为
0(自己到自己步数为 0)
-
-
bfs搜索**(只要队列不为空,就重复)**
-
取出队头坐标,作为当前位置
-
往上下左右 4 个方向尝试走一步
-
对下一步坐标做 3 个判断:
-
没越界
-
没走过(dist = -1)
-
不是墙(g = 0)
-
-
满足条件就:
-
记录距离 = 当前距离 + 1
-
把新坐标加入队列
-
-
如果走到终点 (n,m),直接返回距离(BFS 第一次到达就是最短)
-
代码
cpp
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
typedef pair<int, int> PII;// 存储坐标
const int N = 110;
int n, m;
int g[N][N];//用于存储地图
int dist[N][N];//用于存储每个点到起点的距离
queue<PII> q;
//定义方向数组
int dx[] = {-1,0,1,0};
int dy[] = {0,1,0,-1};
//两个参数是起点的坐标
int bfs(int x, int y){
//初始化所有点到起点的距离为-1 ----这里使用memset函数
memset(dist, -1, sizeof(dist));
//起点入队列
q.push({x,y});
//修改距离数组
dist[x][y] = 0;
//当队列不为空的时候开始广度搜索
while(!q.empty()){
//取出队头
auto t = q.front();
//出队
q.pop();
//进行向上下左右四个方向走
for(int i = 0; i < 4; i++){
//求出下一步的横纵坐标
int a = t.first + dx[i];
int b = t.second + dy[i];
//判断是否越界
if(a < 1 || a > n || b < 1 || b > m){
continue;
}
//判断该点是否已经走过
if(dist[a][b] > -1){
continue;
}
//判断g数组是否为0
if(g[a][b] != 0){
continue;
}
//将更新后的坐标进队列
q.push({a,b});
//更新距离数组
dist[a][b] = dist[t.first][t.second] + 1;
//如果已经到(n,m)了
if(a == n && b == m){
//返回结果
return dist[n][m];
}
}
}
//返回距离
return dist[n][m];
}
int main(){
cin>>n>>m;
//输入地图
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
cin>>g[i][j];
}
}
//广度优先搜索--- 得到最少移动次数
int res = bfs(1,1);
//输出结果
cout<< res <<endl;
}
四、总结
如果每条边的权重都相等,则bfs算法可以求的最短路。
