当前位置:   article > 正文

浅谈(保姆级讲解)宽度优先搜索(bfs)_宽度优先搜索的性质

宽度优先搜索的性质

一.什么是宽度优先搜索

从字面意思上说(比较正规,看看就行):

宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。

从图上来看(这个更易于理解):

现在有一棵树(地图),在这个上面我们现在在A点,但如果我们想去G点,那么bfs算法中

要求我们寻找的时候宽度优先即横着找。因此如果要找从A点到G点的最短路径,我们会先找A,当这一行找完之后,再找B点、C点、D点,第二行找完之后,我们接着第三行展开找E点知道找到G点,这是就大功告成了。

但为什么这样找?我们先看一个例子。

走迷宫
给定一个n*m的二维整数数组,用来表示一个迷宫,数组中只包含0或1,其中0表示可以走的路,1表示不可通过的墙壁。
最初,有一个人位于左上角(1, 1)处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。
请问,该人从左上角移动至右下角(n, m)处,至少需要移动多少次。
数据保证(1, 1)处和(n, m)处的数字为0,且一定至少存在一条通路。

输入格式
第一行包含两个整数n和m。
接下来n行,每行包含m个整数(0或1),表示完整的二维数组迷宫。

输出格式
输出一个整数,表示从左上角移动至右下角的最少移动次数。

数据范围

1≤n,m≤100
1
输入样例:

5 5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
1
2
3
4
5
6
输出样例:

8

我们可以在每次出发的时候,走到离自己最近的点(贪心思想),由此我们每次都保证走最近的,那从局部最近推整体最近,直到走到终点,必有一条路是整体最近的。所以我们可以利用BFS做最短路问题。

在这个迷宫当中,我们要走到(n,m)点的话是不能用dfs广度搜索一条道走到黑的,我们需要稳扎稳打,走一个点记录一个点,只要走到(n,m)点都记录完为止。这就是现在说的bfs算法。

二.代码(板子)

1.待我先解释一下为什么要用队列(用来解决移动到哪个点):

对于上面那个图,我们从A点开始时,让A点入队,对A点附近的点进行查找

之后A点附近搜索完之后,A点出队,让B点、C点、D点入队:

直到最后一直进行这个步骤:

2.上面解决了移动到哪个点的问题,我们接着解决怎么移动的问题:

int dx[4]={0,0,-1,1};//表示要走的四个方向

int dy[4]={1,-1,0,0};

我们使用这两行代码,对于一个点(x,y)坐标表示,如果想向左移动,就是x+(-1),y+0,那么向右就是x+1,y。

这是当我们到达点B后,我们让点B的x、y加上4个不同的移动方向,这时向上走会遇到A点向右走会遇到D点,这样就会把周围点搜索一遍。

注:同时要记得标记一下用过的点,确保不会重复使用。

  1. for(int i=0;i<4;i++){
  2. int nex=top.first+dx[i];
  3. int ney=top.second+dy[i];
  4. //如果某一个方向的下一个位置没有走过,并且位置为零(即此题中可以通过)
  5. //记录此点,同时让该点入队,下一次以此点展开搜索
  6. if(nex>=0&&nex<n&&ney>=0&&ney<m&&mark[nex][ney]==-1&&mp[nex][ney]==0){
  7. mark[nex][ney]=mark[top.first][top.second]+1;
  8. q.push({nex,ney});
  9. }
  10. }

3.这里我们以上面这道经典题目为例进行代码展示:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int n,m;
  4. int dx[4]={0,0,-1,1};//表示要走的四个方向
  5. int dy[4]={1,-1,0,0};
  6. const int N=110;
  7. int mp[N][N];//用来存储地图
  8. int mark[N][N];//表示是否走过当前位置(未走过为-1),以及走了多远
  9. int ans;
  10. typedef pair<int,int> PII;
  11. void bfs(){
  12. memset(mark,-1,sizeof mark);//都初始化为-1表示没有来过
  13. queue<PII> q;
  14. q.push({0,0});//让起点入队
  15. mark[0][0]=0;
  16. while(!q.empty()){
  17. PII top=q.front();//以队列每个元素为起点展开四个方向的搜索
  18. for(int i=0;i<4;i++){
  19. int nex=top.first+dx[i];
  20. int ney=top.second+dy[i];
  21. //如果某一个方向的下一个位置没有走过,并且位置为零(即此题中可以通过)
  22. //记录此点,同时让该点入队,下一次以此点展开搜索
  23. if(nex>=0&&nex<n&&ney>=0&&ney<m&&mark[nex][ney]==-1&&mp[nex][ney]==0){
  24. mark[nex][ney]=mark[top.first][top.second]+1;
  25. q.push({nex,ney});
  26. }
  27. }
  28. q.pop();//当这个节点搜索结束则出队
  29. }
  30. cout<<mark[n-1][m-1]<<endl;//输出最短路结果
  31. }
  32. int main(){
  33. cin>>n>>m;
  34. for(int i=0;i<n;i++){
  35. for(int j=0;j<m;j++){
  36. cin>>mp[i][j];
  37. }
  38. }
  39. bfs();
  40. system("pause");
  41. return 0;
  42. }


至此,功德圆满

入坑不易,记得轻轻点一下关注哦

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/386096
推荐阅读
相关标签
  

闽ICP备14008679号