目录

导入

程序理解

例题


首先在开始我们的学习之前,我们需要读者拥有递归的知识基础

并且在学习之前,我先给出BFS的基本代码模型(基本大部分DFS题目都能按照此模型来写)

void dfs(int step){判断边界尝试每一种可能 for(i=1;i<=n;i++){继续下一步 dfs(step+1)}返回
}

下面开始我们的学习

导入

首先介绍一下DFS

所谓的DFS在我看来就是一条路走到黑,直到无路可走的情况下,才会选择回头,然后重新选择一条路(官方说法即“优先考虑深度”)

引导题:输入一个数n,输出n的全排列
可以先把这个问题形象化
如:

假如有编号为1,2,3的3张扑克牌和编号为1,2,3的3个盒子。将这3张扑克牌分别放入3个盒子一共有几种不同的放法呢?

OK,那么我们就按照DFS的定义“一条路走到底”

那么小明现在走到1号箱子面前,放入1号扑克;再走到2号箱子面前,放入2号扑克;走到3号箱子面前,放入3号扑克;好了我们已经成功“一条路走到底了”,这也是我们的第一种放法

完成第一种排列后,小明便要回头了,开始重新选择(DFS的思想),这里要注意,不是把所以的牌都取出来重新放,那样就不符合DFS的思想了

好的!按照上面的逻辑。小明将3号盒子的3号扑克牌取出,但手上仍然只有3号扑克牌。
所以小明只好回到2号盒子,收回2号扑克牌,此时手中有2,3号扑克牌。
按照之前的约定,往2号盒子放3号扑克牌,然后小明又继续往前走,此时手里只有2号扑克牌,把2号扑克牌放入3号盒子里,此时完成了第二种排序。
按照这种逻辑,我们不难求出所有排列“123”,“132”,“213”,“231”,“312”,“321”

程序理解

说了这么多,应该对DFS有了大概的了解吧。下面用程序来加深大家对DFS的认识。
可能大家会有疑惑,怎么才能往小盒子里放扑克牌呢?
其实很简单,只需要一个for循环就行了。

for(int i=1;i<=n;i++)a[step]=i;//将i号扑克牌放到第step个盒子中

这里的数组a是用来表示盒子的,变量step表示当前处于第step个盒子面前。
这里还有一个问题:如果一张扑克牌已经放入别的盒子里了,该怎么样才能使这张扑克牌不放到当前的盒子里。
其实很简单,只需要再重新创建一个数组book用来标记,看扑克牌是否被使用。

for(int i=1;i<=n;i++){if(book[i]==0){   //说明i号扑克牌还在手里,需要放入step号盒子a[step]=i;//将i号扑克牌放到第step个盒子中book[i]=1;//此时i号扑克牌已经被使用}}

那么接下来如何表示step+1呢?难道要一个函数一个函数这样写吗?其实不需要这么麻烦。
只需要把处理第step的代码封装成一个函数就可以了。

void  dfs(int step){ //此时在第step盒子面前,需要往里面放第i张扑克牌for(int i=1;i<=n;i++){if(book[i]==0){   //说明i号扑克牌还在手里,需要放入step号盒子a[step]=i;//将i号扑克牌放到第step个盒子中book[i]=1;//此时i号扑克牌已经被使用}}
}

接下就是处理第step+1的具体代码了

void  dfs(int step){ //此时在第step盒子面前,需要往里面放第i张扑克牌for(int i=1;i<=n;i++){if(book[i]==0){   //说明i号扑克牌还在手里,需要放入step号盒子a[step]=i;//将i号扑克牌放到第step个盒子中book[i]=1;//此时i号扑克牌已经被使用dfs(step+1);/*注意这里是自己调用自己,表示此时走到了第step+1个盒子面前*/      book[i]=0;/*book[i]=0表示dfs调用结束了,换句话说就是扑克牌已经全部放完了需要按照顺序将扑克牌收回,重新放,也就是前面所说的*/}}
}

说到这里,是不是已经能够理解dfs。现在还要进行最后一步:程序结束的标志和完整的代码

#include<bits/stdc++.h>
using namespace std;const int MAXN=88;
int num[MAXN];//存储每个箱子里面的扑克牌号码
int book[MAXN]={0};//判断扑克牌是否使用过
int n,total=0;
void dfs(int box)
{if(box==n+1){for(int i=1;i<=n;i++){printf("%d ",num[i]);}printf("\n");total++;return ;}    /* 注意这个 return 它的作用不是返回主函数,而是返回上一级的dfs函数例:如果此时是  dfs(5),遇到这个 return 就会回到上一级的 dfs函数 也就是dfs(4),但此时dfs(4)的大部分语句已经执行了,只需要接着执行 book[i]=0然后继续进入for循环进入下一次的 dfs函数,直到结束。       */ for(int i=1;i<=n;i++)//遍历所有的扑克牌号码{if(book[i]==0){num[box]=i;//将扑克牌放到箱子中 book[i]=1;//记录使用过的扑克牌 dfs(box+1);book[i]=0;//“将扑克牌拿出来 ”         }} return ;//这里表示这一级别的dfs函数已经结束了,返回上一级 dfs函数
}int main()
{cin>>n;//输入我们手里有多少扑克牌    dfs(1);//从第一个箱子开始搜索 cout<<"总共有"<<total<<"种放法"<<endl;return 0;
}

相信大家已经能理解dfs了吧。其实要理解dfs的关键在于解决“当下该怎么做”和“下一步如何做

(如果仍然无法理解的话,最后自己一步一步调试来进行理解)

例题

例题 9个数凑一个等式,其中每个数由3个数字组成

思路

初看这个题目,其实最容易想到的其实是暴力枚举,如果用暴力枚举的话,则需要用到9重for循环,而且每个数都不能相同。在这里就不用这种方法了。
接下来就来看看dfs的用法吧(可以向右划)

#include<bits/stdc++.h>
using namespace std;const int MAXN=88;
int num[MAXN];//存储每个箱子里面的扑克牌号码
int book[MAXN]={0};//判断扑克牌是否使用过
int n,total=0;
void dfs(int box)
{if(box==10)//9个箱子都放入数字后 {if(num[1]*100+num[2]*10+num[3]+num[4]*100+num[5]*10+num[6]==num[7]*100+num[8]*10+num[9])//箱子里组成的数字能不能组成等式 {printf("%d+%d=%d\n",num[1]*100+num[2]*10+num[3],num[4]*100+num[5]*10+num[6],num[7]*100+num[8]*10+num[9]);total++;}return ;} for(int i=1;i<=9;i++)//遍历所有的扑克牌号码{if(book[i]==0){num[box]=i;//将扑克牌放到箱子中 book[i]=1;//记录使用过的扑克牌 dfs(box+1);book[i]=0;//“将扑克牌拿出来 ”        }} return ;
}int main()
{dfs(1);//从第一个箱子开始搜索 cout<<"总共有"<<total/2<<"种放法"<<endl;return 0;
}

迷宫问题

题目大概意思:处于迷宫入口的小明(1,1),寻找位于(p,q)的小红,也就是最短路径问题 其中n表示行,m表示列

看到这个题目的时候用DFS,感觉就是四处碰壁,最后才走向成功。也就是指把所有的情况都发生一次,才知道最好的选择并输出。

首先要把这个迷宫看作一个二维数组,每走一步就相当于x或者y变化

接下来看看如何表示小明走一步吧!其实很简单,只需要用一个二维数组就行了哦。

int next[4][2]={{0,1), //向右走一步{1,0},//向下走一步{0,-1},//向左走一步{-1,0}};//向上走一步

下面的一张图,就更方便大家理解了,正好与上面的源码对应。

通过这个方向数组,使用循环就很容易获得下一步的坐标。这里可以用tx,xy来表示。

for(k=0;k<=3;k++){   //下一步的坐标tx=x+next[k][0]; //下一步的坐标:当前的+下一步要走的ty=y+next[k][1];//下一步坐标:当前的+下一步要走的
}

下面来对下一点(tx,ty) 进行一些判断。
包括是否越界,是否为障碍物,已经这个点是否被访问。所以也要一个book[tx][ty]来记录点是否被访问。如果这个点符合所有要求,就继续寻找下一个点,也就是 dfs( tx,ty,step+1)。
注意:a[][]等于0表示该点不是障碍
还有book[][]等于0表示该点还没走过
下面就是具体的代码

其实到这里也就差不多了,但还有最后一步。如何判断小明已经找到小红了。不多说了,看代码吧!

#include<iostream>
using namespace std;int MIN = 10000;
int book[100][100] = { 0 };
int MAP[100][100];
int next_[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};//右 下 左 上
int tx, ty, p, q,n,m;void dfs(int x, int y, int step)
{if (x == p && y == q)//找到小红 {if (step < MIN){MIN = step;}return;}for (int z = 0; z <= 3; z++){tx = x + next_[z][0];//下一步 ty = y + next_[z][1];//下一步 if (tx<1 || tx>n || ty<1 || ty>m)//是否越界 {continue;}if (book[tx][ty] == 0 && MAP[tx][ty] == 0){book[tx][ty] = 1;dfs(tx, ty, step + 1);book[tx][ty] = 0;}}return;}int main()
{int i, j, start_x, start_y;cin >> n >> m;//输入迷宫大小(n表示行,m表示列) for (i = 1; i <= n; i++){for (j = 1; j <= m; j++){cin >> MAP[i][j];}}cin >> start_x >> start_y;//输入“我的起点 ”cin >> p >> q;book[start_x][start_y] = 1;//初始化起点 dfs(start_x, start_y, 0);//从0步开始记录步数cout << MIN << endl;return 0;
}

总的来说,BFS由于涉及到递归的思想,理解上还是比较困难的,大家学习完记得做相关的题目巩固知识点哟!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

DFS(深度优先搜索算法)入门相关推荐

  1. 算法导论:dfs深度优先搜索算法及基于dfs的拓扑排序以及宽度优先搜索算法bfs

    1.dfs深度优先搜索算法 算法导论中是通过三种标记颜色来介绍dfs的,white代表还没被搜过,grey代表被搜了一些,还没结束,white表示已经搜索完成的状态. c/c++复现dfs代码 #in ...

  2. DFS深度优先搜索算法/BFS广度优先搜索算法(c/c++)

    深度优先搜索算法(DFS) 深度优先搜索算法思路:(有点贪心算法的意思) 1,从某个给定结点a出发,访问它 2,查找关于a的邻接点,查找到a的第一个邻接点b之后,对b结点进行DFS搜索,也就是对b结点 ...

  3. DFS(深度优先搜索算法)

    基本概念 深度优先搜索算法(Depth First Search,简称DFS):一种用于遍历或搜索树或图的算法. 沿着树的深度遍历树的节点,尽可能深的搜索树的分支.当节点v的所在边都己被探寻过或者在搜 ...

  4. opencv制作微信小游戏 最强连一连 辅助(2)--dfs深度优先搜索算法

    深度优先搜索算法还是大二上数据结构的时候学的,工作以后都忘得差不多了.赶紧回来温习一下吧. 深度优先搜索的算法的 入参是一个地图(一般可以用二维数组表示)和一个起始点. 比如 这个就是一个5*5的二维 ...

  5. DFS(深度优先搜索算法)——Java实现(含例题)

    基本概念 深度优先搜索算法(Depth First Search,简称DFS):一种用于遍历或搜索树或图的算法. 沿着树的深度遍历树的节点,尽可能深的搜索树的分支.当节点v的所在边都己被探寻过或者在搜 ...

  6. C语言 DFS(深度优先搜索算法) 详解

    基本概念 深度优先搜索算法(Depth First Search,简称DFS):一种用于遍历或搜索树或图的算法. 沿着树的深度遍历树的节点,尽可能深的搜索树的分支.当节点v的所在边都己被探寻过或者在搜 ...

  7. 蓝桥杯Java——DFS深度优先搜索算法

    目录 基本概念 算法思想 模板 例子 基本概念 深度优先搜索算法(Depth First Search,简称DFS):一种用于遍历或搜索树或图的算法. 沿着树的深度遍历树的节点,尽可能深的搜索树的分支 ...

  8. 详解ACM基础算法—DFS深度优先搜索算法 HIT杨朔

    深度优先搜索(DFS)是搜索手段之一.是从某个状态开始不断转移状态直到无法转移为止,然后退回到前一步状态继续转移其他状态,可以想象为一个沿树爬行的虫子,在一个交叉口他会首先随机选择一条分岔路口一直走下 ...

  9. (6)DFS(深度优先搜索算法):n皇后问题

    题解: 作者:yxc 链接:https://www.acwing.com/activity/content/code/content/47097/ 来源:AcWing 第一种搜索顺序 附代码: #in ...

  10. (5)DFS(深度优先搜索算法):排列数字

    题解: 附代码: #include<iostream> using namespace std;const int N=10;int n; int path[N];//将每个节点的数据用数 ...

最新文章

  1. java tooltips_一款使用纯javacript编写的轻量级tooltips工具
  2. AutoML前沿技术与实践经验分享 | 免费公开课
  3. COOKIE和SESSION关系和区别
  4. BASH SHELL 脚本基础
  5. python中pow是什么函数_python中pow什么意思
  6. ubyntu 链接mysql_ubuntu mysql 的安装、配置、简单使用,navicat 连接
  7. vant toast loading 倒计时_日期倒计时软件哪个好 苹果日期倒计时软件推荐
  8. 用计算路由的方法优化BI后台性能
  9. python和excel能结合应用吗_通过Python在Excel中使用机器学习
  10. iview使用之怎样通过render函数在table组件表头添加图标及判断多个状态
  11. 下轮“双一流”将有高校下车?教育部最新说法来了!
  12. 成都领君科技自然资源一张图平台设计方案
  13. 继续教育计算机组成原理a试卷,计算机组成原理试卷.docx
  14. 如何高效地阅读技术类书籍与博客
  15. 外贸常用术语_13个常用的国际贸易术语详解
  16. matlab在c盘有缓存文件夹吗,win10如何清除C盘缓存文件-win10清除C盘缓存的方法 - 河东软件园...
  17. xshell对mysql的备份与恢复_XShell5里面登陆了数据库,如何将数据库里面的表或者整个数据库备份导出来(和导入进去)...
  18. 华为手机nova计算机怎么找过程,华为nova手机拆机全过程 华为nova真机拆解图解教程...
  19. C#基础------常用软件官方下载
  20. EOJ Monthly 2018.12 B. 清点星辰(蒙特卡洛模拟)

热门文章

  1. SVG文档:使用SVG 编程(转自IBM文档库)
  2. 仿乐享微信营销服务系统源码免费下载
  3. php怎么把多个pdf拼接成一个,如何把PDF文件拼接成一个?
  4. PAT (Basic Level) Practise (中文)1022. D进制的A+B (20)
  5. 复旦大学2019计算机考研,2019年复旦961软件工程专硕考研初试363+复试经验分享
  6. Mac 解压缩rar文件
  7. iOS 手机常见功能总结(一)
  8. Android图片不规则裁剪
  9. FastJSON处理对象中属性值为空的数据
  10. 九轴传感器姿态----AHRS算法开源项目推荐