BFS(广度优先搜索)
定义
广度优先搜索:总是以“广度”为第一关键词,碰到“岔道口”时,总是依次访问该岔道口能直接到达的所有节点(与初始状态越接近就越先访问),再按照它们被访问的顺序访问他们能直接到达的所有节点,以此类推
实现
根据广度优先搜索的特点,它往往使用队列实现
适用问题
BFS一般适用于最短路问题,在解的分布较为稀疏时,使用DFS会较慢,此时也可以考虑使用BFS
BFS伪代码描述(模板)
memset(ans, -1, sizeof(ans))//将保存的状态数组初始化,以便于确认是否访问过
void bfs(){
queue<int> q;//也可定义在全局变量中
q.push(s);//s为初始状态,即将初始状态入队
while(!q.empty()){//循环到队列为空
state now = q.front();//取出队首并保存,state根据题目需要而定
//此时可以根据需要访问队首
q.pop;//队首出队
for(枚举所有可扩展状态){//扩展,即可以“往下走”的状态
if (合法){//合法是指:未访问过,未在队内,满足题目限制条件
q.push(合法节点);//将其入队,并根据题目要求进行维护
}
}
}
}
经典例题
洛谷P1443 马的遍历
题目描述
有一个 n × m n\times m n×m的棋盘( 1 < n , m ≤ 400 1<n,m\le 400 1<n,m≤400),在某个点上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步,马的走法与国际象棋或中国象棋走法相同
输入格式
一行四个数据,棋盘的大小和马的坐标
输出格式
一个n*m的矩阵,代表马到达某个点最少要走几步(左对齐,宽5格,不能到达则输出-1)
输入输出样例
输入
3 3 1 1
输出
0 3 2 3 -1 1 2 1 4
思路解析
题干中“最少几步”,我们可以考虑使用BFS做题
源代码
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
const int maxn = 400;
struct coord{//用结构coord保存坐标值
int x;
int y;
};
queue<coord> q;
int ans[maxn][maxn];//保存答案
int walk[8][2] = {{2, 1}, {1, 2}, {-1, 2}, {-2, 1},
{-2, -1}, {-1, -2}, {1, -2}, {2, -1}};//用增量数组表示前进方向,便于枚举
int main() {
int n, m, sx, sy;//棋盘大小和起始坐标
memset(ans, -1, sizeof(ans));//初始化
cin >> n >> m >> sx >> sy;
//BFS
coord tmp = {sx, sy};//
q.push(tmp);//使用变量tmp存放初始坐标,并将其入队
ans[sx][sy] = 0;//初始化ans[sx][sy]
while(!q.empty()){
//u变量用于保存每一次的队首
coord u = q.front();
int ux = u.x, uy = u.y;
q.pop();//队首出队
for (int i = 0; i < 8; ++i) {
int x = ux + walk[i][0];
int y = uy + walk[i][1];
int d = ans[ux][uy];
if (x < 1 || x > n || y < 1 || y > m || ans[x][y] != -1)
continue;//遍历原始量+增量,若不合法则continue
ans[x][y] = d + 1;//上一个点多走一步就到了这一个点
coord tmp = {x, y};
q.push(tmp);//这一个点入队
}
}
for (int i = 1; i <= n; ++i, puts("")) {
for (int j = 1; j <= m; ++j) {
printf("%-5d", ans[i][j]);//按要求输出结果
}
}
return 0;
}