深度优先搜索DFS和广度优先搜索BFS简单解析

与树的遍历类似,图的遍历要求从某一点出发,每个点仅被访问一次,这个过程就是图的遍历。图的遍历常用的有深度优先搜索和广度优先搜索,这两者对于有向图和无向图均适用。

一.深度优先搜索

1.理解分析

首先,让我们来看一看更些简单的深度优先搜索DFS。顾名思义,这个搜索方法是以深度优先,也就是先一条路走到黑,撞到南墙再回头。我们可以看做是一棵树,优先走到根部,然后换一根继续走到最后。下面给出一张图便于理解。

我们可以看到,我们先从V1出发前往V2,然后继续往更深的地方出发,前往V5,V9,然后由于V9是根的最深处,于是我们返回上一层(V5所在),发现还有一个V10没有搜索,所以我们前往V10,然后由于V10是最深的地方,接着往回上一层(V5所在),看看是否还有没有访问搜索的点,发现没有,接着返回上一层(V2所在),发现还有一个V6没有访问,于是搜索访问V6。如此重复,这样就是深度优先搜索。

我们来仔细思考下这个过程,有没有发现和递归有着类似之处?

我们来看一看,第一次调用,我们可以理解为目前处于第二层搜索V2节点,第二次调用,我们可以理解为DFS里搜索该节点下的第三层节点,调用完成后结束调用可以看做返回第一层,这样,其中一条V2及以下都已经被遍历过,重复过程,改变参数,我们可以使得所有都被遍历过一次。所以,我们一般采用递归的方法来实现DFS。

2.例题分析

https://vjudge.net/problem/HDU-1241

油田问题可以说是经典的使用DFS解决的问题了。

Input:

Output:

2

输入的第一行是油田行数和列数,@符号代表油田,我们要求的是的 @ 符号连成一块地(横竖斜相连都算),能有几块这样的油田地。

下面给出代码:

  1. #include<iostream>
  2. #include<queue>
  3. #include<cstring>
  4. #include<cstdio>
  5. using namespace std;
  6. int map[150][150];//用来记录该地是否被查询过,0代表没有
  7. int x, y;
  8. char p[150][150];//存放油田
  9. int find(int a, int m, int n)
  10. {
  11. if (map[m][n] != 0|| p[m][n] != '@')//当不是油田(也就是搜索到头了),并且被找过了,则返回0
  12. return 0;
  13. else
  14. {
  15. map[m][n] = a;
  16. //下面这些就是递归部分,写成这样分开便于理解
  17. //先一直往横坐标加1,往右侧不断查询,以下同理
  18. find(a, m + 1, n);
  19. find(a, m + 1, n + 1);
  20. find(a, m + 1, n - 1);
  21. find(a, m, n + 1);
  22. find(a, m, n - 1);
  23. find(a, m - 1, n + 1);
  24. find(a, m - 1, n);
  25. find(a, m - 1, n - 1);
  26. }
  27. return 0;
  28. }
  29. int oilPocket(int a)
  30. {
  31. int i, j;
  32. for (i = 0; i < x; i++)
  33. {
  34. for (j = 0; j < y; j++)
  35. {
  36. if (map[i][j] == 0 && p[i][j] == '@')
  37. { //当遇到一块油田没有被遍历过,则以这个点进行深度优先搜索
  38. find(a, i, j);//a代表这块大油田地是第几块,ij就是坐标
  39. a++;
  40. }
  41. }
  42. }
  43. return a;
  44. }
  45. int main()
  46. {
  47. int ans;
  48. while (scanf("%d %d", &x, &y) != EOF)
  49. {
  50. if (x == 0 || y == 0) break;
  51. memset(p, '*', sizeof(p));
  52. for (int i = 0; i < x; i++)
  53. {
  54. cin.get();//存回车
  55. for (int j = 0; j < y; j++)
  56. {
  57. scanf("%c", &p[i][j]);
  58. }
  59. }
  60. memset(map, 0, sizeof(map));
  61. ans = oilPocket(1) - 1;
  62. printf("%d\n", ans);
  63. }
  64. return 0;
  65. }

这段代码主要是find函数部分,我们可以看到,每次递归都是一开始往右侧找,找到头后往下找,每次都是有着固定的方向,一路寻找到头,然后才会改变方向。这样,我们就使用DFS成功地求得连接在一起的油田数量。

  • 有一点在写深度优先搜索时容易犯错误,那就是注意要判断该点是否查询过,反复查询会导致无限递归从而程序出现错误。

二.广度优先搜索

1.理解分析

和深度优先搜索不同的是,我们先访问的是同一层未被搜索过的点,当该层搜索完毕后,我们才会往下一层进发,开始下一层的搜索。

由图我们可以看到我们从V1开始,选择搜索V2,接下来并没有同深度优先搜索一样,搜索V5,而是接着看看同层是否有未被搜索过的点,我们发现V3没有被搜索过,所以我们接着搜索V3,知道V3,V4都被搜索过,我们才开始往下一层进发,搜索V5,V6......

接着,我们来仔细想想,我们该怎么实现BFS呢?

我们发现,如果我们把同一层的点存起来,那么,先进先出的话,同层点在被访问过后,才会接着访问下一层的点。而先进先出正是队列的特点,所以,我们可以使用队列来实现BFS。

2.例题分析

https://vjudge.net/problem/HDU-1548

奇怪的电梯,可以使用BFS来解决,当然也可以使用DFS和Dijkstra

来解决(有兴趣可以尝试下)

奇怪的电梯题目输入是当前所在楼层,目的楼层,楼层总数,每层电梯只能上下的层数。

输出是最少的次数,不能到达则-1。

  1. #include <queue>
  2. #include <iostream>
  3. #include <cstring>
  4. using namespace std;
  5. queue <int> q;
  6. int num,s,e;
  7. int a[1000];
  8. int step[1000];
  9. void bfs(){
  10. int m,n;
  11. while(!q.empty())
  12. {
  13. m = q.front();//取出当前队列第一个数,即当前楼层
  14. q.pop();
  15. n = m + a[m];//往上移动到的楼层数
  16. if(n >= 1 && n <= num && step[n] == -1)
  17. {
  18. step[n] = step[m] + 1;//步数自增
  19. q.push(n);//把当前(移动后的)楼层数加入队列
  20. }
  21. n = m - a[m];//往下移动到的楼层数
  22. if(n >= 1 && n <= num && step[n] == -1)
  23. {
  24. step[n] = step[m] + 1;//步数自增
  25. q.push(n);//把当前(移动后的)楼层数加入队列
  26. }
  27. }
  28. //队列为空,则表示没有可以移动的位置了,即所有能走的楼层均走过
  29. cout << step[e] << endl;
  30. }
  31. int main(){
  32. while(scanf("%d",&num)!= EOF)
  33. {
  34. if(num == 0)
  35. {
  36. break;
  37. }
  38. scanf("%d%d",&s,&e);//开始结束楼层
  39. for(int i = 1 ; i <= num ; i++)
  40. {
  41. scanf("%d",&a[i]);//每层固定上下移动的层数
  42. }
  43. memset(step,-1,sizeof(step));
  44. step[s] = 0;
  45. q.push(s);//将开始层数加入队列
  46. bfs();
  47. }
  48. return 0;
  49. }

BFS对于求无权路的最短路径很方便,遍历一遍,到了对应的节点,则可以说是最短路径,对于有权图可以采用Dijkstra等等。

三.总结

BFS和DFS主要是一种遍历图的方式,理解透彻具体是什么,该怎么遍历,熟练之后便可以很快上手,那么该怎么熟练呢?当然是理解+刷题(笑。再来推荐道题目Serial Time! ,DFS,BFS都可以尝试下(逃

深度优先搜索DFS和广度优先搜索BFS简单解析(新手向)的更多相关文章

  1. 深度优先搜索DFS和广度优先搜索BFS简单解析

    转自:https://www.cnblogs.com/FZfangzheng/p/8529132.html 深度优先搜索DFS和广度优先搜索BFS简单解析 与树的遍历类似,图的遍历要求从某一点出发,每 ...

  2. 图的遍历(搜索)算法(深度优先算法DFS和广度优先算法BFS)

    图的遍历的定义: 从图的某个顶点出发访问遍图中所有顶点,且每个顶点仅被访问一次.(连通图与非连通图) 深度优先遍历(DFS): 1.访问指定的起始顶点: 2.若当前访问的顶点的邻接顶点有未被访问的,则 ...

  3. 深度优先搜索DFS和广度优先搜索BFS

    DFS简介 深度优先搜索,一般会设置一个数组visited记录每个顶点的访问状态,初始状态图中所有顶点均未被访问,从某个未被访问过的顶点开始按照某个原则一直往深处访问,访问的过程中随时更新数组visi ...

  4. 图的深度优先搜索(DFS)和广度优先搜索(BFS)算法

    深度优先(DFS) 深度优先遍历,从初始访问结点出发,我们知道初始访问结点可能有多个邻接结点,深度优先遍历的策略就是首先访问第一个邻接结点,然后再以这个被访问的邻接结点作为初始结点,访问它的第一个邻接 ...

  5. 图的 储存 深度优先(DFS)广度优先(BFS)遍历

    图遍历的概念: 从图中某顶点出发访遍图中每个顶点,且每个顶点仅访问一次,此过程称为图的遍历(Traversing Graph).图的遍历算法是求解图的连通性问题.拓扑排序和求关键路径等算法的基础.图的 ...

  6. 图的深度优先遍历(DFS)和广度优先遍历(BFS)

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  7. 【C++】基于邻接矩阵的图的深度优先遍历(DFS)和广度优先遍历(BFS)

    写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文! 本博客全网唯一合法URL:ht ...

  8. 图的深度优先遍历(DFS)和广度优先遍历(BFS)算法分析

    1. 深度优先遍历 深度优先遍历(Depth First Search)的主要思想是: 1.首先以一个未被访问过的顶点作为起始顶点,沿当前顶点的边走到未访问过的顶点: 2.当没有未访问过的顶点时,则回 ...

  9. 深度优先搜索(DFS)和广度优先搜索(BFS)求解迷宫问题

    用下面这个简单的迷宫图作为例子: OXXXXXXX OOOOOXXX XOXXOOOX XOXXOXXO XOXXXXXX XOXXOOOX XOOOOXOO XXXXXXXO O为通路,X为障碍物. ...

随机推荐

  1. linux命令dd

    原文链接: http://blog.csdn.net/adaptiver/article/details/6672592 dd 使用dd这个linux命令可以创建一定大小文件. linux创建文件命令 ...

  2. UOJ Round #1 [数论 | DP 排列]

    UOJ Round #1 难度很良心啊! 做出了前两题,第三题看到仙人掌就吓哭了. [UR #1]缩进优化 就是求 \[ \sum_{i=1}^n a_i - (x-1)\sum_{i=1}^n\lf ...

  3. bzoj 3812: 主旋律 [容斥原理 状压DP]

    3812: 主旋律 题意:一张有向图,求它的生成子图是强连通图的个数.\(n \le 15\) 先说一个比较暴力的做法. 终于知道n个点图的是DAG的生成子图个数怎么求了. 暴力枚举哪些点是一个scc ...

  4. 万类之父——Object

    jdk1.8.0_144 Object类作为Java中的顶级类,位于java.lang包中.所有的类直接或者间接都继承自它.所以Object类中的方法在所有类中都可以直接调用.在深入介绍它的API时, ...

  5. asp.net core 使用html文件

    在asp.net core 项目中,使用html文件一般通过使用中间件来提供服务: 打开 NuGet程序管理控制台 输入install-package Microsoft.aspnetcore.sta ...

  6. grep命令的-P选项

    man grep的时候有一个-P,文档上的英文: -P, --perl-regexp Interpret PATTERN as a Perl regular expression.  This is ...

  7. Java中从键盘输入的三种方法

    import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import ...

  8. Sping Boot入门到实战之入门篇(三):Spring Boot属性配置

    该篇为Sping Boot入门到实战系列入门篇的第三篇.介绍Spring Boot的属性配置.   传统的Spring Web应用自定义属性一般是通过添加一个demo.properties配置文件(文 ...

  9. UVA1213

    先打表,再回溯+剪枝 AC代码: #include<cstdio> #include<cstring> #include<cmath> const int maxn ...

  10. 历届试题 大臣的旅费 树形DP

    题目链接:大臣的旅费 思路:锦囊说用广搜,可惜这题没说数据范围,担心复杂度太高,我就直接用的树形DP--求树的最远路径. 以城市1为整棵树的根结点,d(i)表示以i为根结点的子树的最远路径,还有一个f ...