好的,上次讲的深搜DFS获得小众好评,我肯定要水写一下广搜的blog呀!!!
(其实就是因为上次吐槽的太粗略没脸在水别的。。。)
还是再讲一下定义:
宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。
好的,我来解释一下神吐槽时那超恶心友好的代码是怎么回事,还没看过那篇blog的同志们可以去看一下。https://blog.csdn.net/weixin_43417464/article/details/113844226
搜索常见的迷宫问题(用搜索的)有三种形式:
- 能不能到(最好用深搜)
- 最短几步到,无边权值,都是单位边权的那种(最好用广搜)
- 唯一最短路怎么走,无边权值,都是单位边权的那种(最好用广搜)
能不能到之前讲过了,还不会的去看一下呗:https://blog.csdn.net/weixin_43417464/article/details/113061870
直接开讲第二种。
有道这个的模板题,去做一下。http://ybt.ssoier.cn:8088/problem_show.php?pid=1252
先用老少皆宜的深搜做一下:
#include<bits/stdc++.h>
using namespace std;
int minn=0x3f3f3f3f,n,m,ex,ey,vis[101][101],mmap[101][101];
int dis[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
void dfs(int ax,int ay,int depth){
if(ax==ex&&ay==ey){
if(depth<minn) minn=depth;
return ;
}
for(int i=0;i<4;i++){
int dx=ax+dis[i][0],dy=ay+dis[i][1];
if(dx>=0&&dy>=0&&dx<n&&dy<m&&mmap[dx][dy]&&!vis[dx][dy]){
vis[dx][dy]=1;
dfs(dx,dy,depth+1);
vis[dx][dy]=0;
}
}
}
int main(){
cin>>n>>m;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
char ch;cin>>ch;
if(ch=='.') mmap[i][j]=1;
else mmap[i][j]=0;
}
ex=n-1,ey=m-1;
dfs(0,0,0);
cout<<minn+1;
return 0;
}
提交一下......
1,6,10AC,其余的是耀眼的TLE
好吧,只能用广搜了......
先讲一下广搜。
首先,广搜和深搜一样,都得保存可移动点的坐标及深度,也就是到那个点的最少步数。
也就是说,我们必须建立一个结构体,结构体的变量来存储它这个变量所有的信息。
因为我们的广搜要用到队列(原因在神吐槽中讲过了),而队列需要存储每一个点的信息,为了方便查询,我们使用结构体队列。
接着我们需要先把起点的相关信息结构体给塞进队列里,在保证队列不为空的情况下,我们一直while,而到了终点站的时候,就可以直接return了。
while里面和深搜大同小异,先把队列首取出来,找到那些队首点能一步到达的点(照样是dx,dy,边界条件来判断)给它塞到队列里面去,没必要在找一步点是就去看他是不是终点,后面总会检查到的。
代码这样写:
#include<bits/stdc++.h>
using namespace std;
int minn=0x3f3f3f3f,n,m,ex,ey,vis[101][101],mmap[101][101];
int dis[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
struct place{
int ax,ay,depth;
};
void bfs(){
queue<place> q;
place front;
front.ax=0,front.ay=0,front.depth=1;
q.push(front);
while(!q.empty()){
front=q.front();
q.pop();
if(front.ax==ex&&front.ay==ey){
minn=front.depth;
return ;
}
for(int i=0;i<4;i++){
int dx=front.ax+dis[i][0],dy=front.ay+dis[i][1];
if(dx>=0&&dy>=0&&dx<n&&dy<m&&!vis[dx][dy]&&mmap[dx][dy]){
vis[dx][dy]=1;
place xxx;
xxx.ax=dx,xxx.ay=dy,xxx.depth=front.depth+1;
q.push(xxx);
}
}
}
}
int main(){
cin>>n>>m;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
char ch;cin>>ch;
if(ch=='.') mmap[i][j]=1;
else mmap[i][j]=0;
}
ex=n-1,ey=m-1;
bfs();
cout<<minn;
return 0;
}
这不就AC了!
接着看第三类:
模板题:http://ybt.ssoier.cn:8088/problem_show.php?pid=1255
曾经我走迷宫时(真实迷宫):
迷宫不会走怎办?上帝视角看一看。太过复杂怎么办?想编程序就完蛋。可是我现在会编了!
只要在结构体里加上父节点(上一步)的坐标,然后专门做一个查询父节点的二维数组,专门用来查询那个节点的父节点;
然后再做一个递归输出的函数,就大功告成了!!!
上代码!!!
#include<bits/stdc++.h>
using namespace std;
int vis[6][6],mmap[6][6];
int dis[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
struct place{
int ax,ay,fx,fy;
}father[6][6],front;
void print(int x,int y){
if(x==-1&&y==-1) return ;
print(father[x][y].fx,father[x][y].fy);
cout<<'('<<x<<", "<<y<<')'<<endl;
}
void bfs(){
queue<place> q;
front.ax=0,front.ay=0,front.fx=-1,front.fy=-1;vis[0][0]=1;
q.push(front);
while(!q.empty()){
front=q.front();father[front.ax][front.ay]=front;q.pop();
for(int i=0;i<4;i++){
int dx=front.ax+dis[i][0],dy=front.ay+dis[i][1];
if(dx>=0&&dy>=0&&dx<5&&dy<5&&!vis[dx][dy]&&!mmap[dx][dy]){
place now;
vis[dx][dy]=1;
now.ax=dx,now.ay=dy,now.fx=front.ax,now.fy=front.ay;
q.push(now);
}
}
}
print(4,4);
}
int main(){
for(int i=0;i<5;i++) for(int j=0;j<5;j++) cin>>mmap[i][j];
bfs();
return 0;
}
你学费了吗?