宽搜问题:相较于DFS,BFS能够找到一条最优解,相当于权值为1的无向图(考虑边界以及下一路径是否能搜寻的问题),BFS其实更为复杂,代码模板使用到队列(c可以使用数组进行队列模拟)
基本思路:首先预处理数组,bfs如何编写:(1)建立队列,预处理起点以及距离 (2)当队列不为空时,取出队头元素开始遍历,一般使用偏移量进行求解 (3)判断下一点是否满足条件,如果满足,更新该点的状态信息(距离、次数等),由于BFS最优解的特性,只有第一次被遍历到才是最短路,所以修改该点的状态为不可被其他结点再次搜到 (4)入队,知道队列为空或者找到满足的条件结束查找。
问题1:走迷宫
有一个人位于左上角 (1,1)(1,1) 处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。请问,该人从左上角移动至右下角 (n,m)(n,m) 处,至少需要移动多少次。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int, int> PII;
const int N = 110;
int d[N][N];//用于存储地图
int g[N][N];//用于存储距离
int n,m;
void bfs()
{
queue<PII> q;
// memset(g, -1, sizeof g);
q.push({0,0});
while(q.size())
{
auto k=q.front();
q.pop();
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
for(int i=0;i<4;i++)
{
int x=k.first+dx[i],y=k.second+dy[i];
if(x>=0&&x<n&&y>=0&&y<m&&g[x][y]==0&&d[x][y]==0){
g[x][y]=g[k.first][k.second]+1;
q.push({x,y});
//g[x][y]=0;
}
}
}
cout<<g[n-1][m-1];
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++) cin>>d[i][j];
}
bfs();
return 0;
}
问题二:八数码问题
在一个 3×3 3×3 的网格中,1∼81∼8 这 8 个数字和一个 x
恰好不重不漏地分布在这 3×3 3×3 的网格中。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <unordered_map>
using namespace std;
int bfs(string start){
queue<string> q;
unordered_map<string,int> m;
string end="12345678x";
q.push(start);
m[start]=0;
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
while(q.size())
{
string k=q.front();
q.pop();
if(k==end) return m[k];
int distance=m[k];
int j=k.find('x');
for(int i=0;i<4;i++)
{
int x=dx[i]+j/3,y=dy[i]+j%3;
if(x>=0&&x<3&&y>=0&&y<3){
swap(k[j],k[x*3+y]);
if(!m.count(k)){
m[k]=distance+1;
q.push(k);
}
swap(k[j],k[x*3+y]);
}
}
}
return -1;
}
int main()
{
char s;
string stage;
for(int i=0;i<9;i++){
cin>>s;
stage+=s;
// cout<<stage<<' ';
}
cout<<bfs(stage);
return 0;
}