BFS我们称之为宽搜,通常可以用于解决最短,最小问题。不同于深搜,宽搜每次先把同一层的遍历一遍,若无正确答案再去遍历下一层,因此不需要用到递归,只需要用到循环即可。
先来看一道经典例题:走迷宫
解决走迷宫问题,我们可以用程序来模拟一下走迷宫,但不同人走迷宫,我们通过程序可以在一个位置从上下左右去尝试,直到找到正确答案。
解决走迷宫问题,我们可以用程序来模拟一下走迷宫,但不同人走迷宫,我们通过程序可以在一个位置从上下左右去尝试,直到找到正确答案。但前提是向该方向走一步后,到达的点是否合法,因此要进行判断。同时如果该点已经走过,那我们也不要再走一遍。
#include<bits/stdc++.h>
using namespace std;
typedef pair<int , int> PII;
const int N = 110;
//g数组用来存储地图,d数组用来每一个点到起始点的距离
int g[N][N] , d[N][N];
int n , m;
//队列,表示当前走到的点
PII q[N * N];
int bfs()
{
//定义队头队尾
int hh = 0 , tt = 0;
//先把第一个点放入当前走的点
q[0] = {
0 , 0};
//初始化d数组,使每个点都没涉足
memset(d , -1 , sizeof d);
//表示第0个点已经走过了
d[0][0] = 0;
//定义了每次的x和y的偏移量
int dx[4] = {
-1 , 0 , 1 , 0};
int dy[4] = {
0 , 1 , 0 , -1};
//
while( hh <= tt )
{
//取队头元素
PII t = q[hh ++ ];
for(int i = 0 ; i < 4 ; i++)
{
int x = t.first + dx[i];
int y = t.second + dy[i];
//判断该点不超出范围,可走并且没走过
if( x >= 0 && x < n && y >= 0 && y < m && g[x][y] == 0 && d[x][y] == -1)
{
//到起始点的距离
d[x][y] = d[t.first][t.second] + 1;
//新点入列
q[ ++tt ] = {
x , y};
}
}
}
return d[n - 1][m - 1];
}
int main()
{
cin >> n >> m;
for(int i = 0 ; i < n ; i++)
{
for(int j = 0 ; j < m ; j++) cin >> g[i][j];
}
cout << bfs() << endl;
return 0;
}
作者:阿柴
链接:https://www.acwing.com/activity/content/code/content/582768/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
宽搜同样总结起来就是:
(1)处理好已经遍历的点
(2)注意同层之间的数据转换关系
(3)一定要还原现场!
接下来来看一道难题
#include<bits/stdc++.h>
using namespace std;
int bfs( string start )
{
string end = "12345678x";
queue<string> q;
unordered_map< string , int > d;
q.push(start);
//startd的初始距离为0
d[start] = 0;
int dx[4] = {
1 , 0 , -1 , 0};
int dy[4] = {
0 , 1 , 0 , -1};
//若队列未空,继续搜索
while( q.size() )
{
//取队列的头元素
auto t = q.front();
q.pop();
if( t == end ) return d[t];
//取出当前状态的距离
int dis = d[t];
//找出x的位置
int k = t.find( 'x' );
//将x的位置转化为二维数组的下标
int x = k / 3 , y = k % 3;
for(int i = 0 ; i < 4 ; i++)
{
for(int j = 0 ; j < 4 ; j++)
{
//将x往四个方向移动
int a = x + dx[i] , b = y + dy[i];
//如果移动后的点没有越界
if( a >= 0 && a < 3 && b >= 0 && b < 3 )
{
swap( t[k] , t[ a * 3 + b ] );
//如果当前状态没有被记录
if( !d.count(t) )
{
//当前状态为上一上一状态的距离+1
d[t] = dis + 1;
//入队
q.push(t);
}
//因为还要判断下一次移动的状态,所以要还原现场
swap( t[k] , t[ a * 3 + b ] );
}
}
}
}
return -1;
}
int main()
{
string start;
for(int i = 0 ; i < 9 ; i++)
{
char x;
cin >> x;
start += x;
}
cout << bfs(start) << endl;
return 0;
}
作者:阿柴
链接:https://www.acwing.com/activity/content/code/content/585447/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。