DFS算法的本质
引言
DFS 俗称深搜,是一种常见的算法模型
我们通过借助函数递归和递归停止条件的运用实现对数据的高级枚举
对于DFS算法而言,最重要的是如何去枚举数据,即如何去搜索?
这是在运用DFS之前我们就应该思考的问题,只有对其思考清楚,才不妨碍我们下一步去运用代码实现DFS!
OK! 让我们开始吧!
何为搜索?
让我们先忘记你学过DFS算法这件事,抛开脑子中具体的代码结构,单纯地以一个自然人地角度去思考,什么是搜索?
单独思考一个词汇可能我们不会获得很多,下面我们借助具体例子来说明:
假如我说——我们去搜索一间房子,你会想到什么?
寻找?探索?还是在房子里面转悠?
可能这么说会引起歧义,这里我们再具体一点
换成——我们去搜索这间房子,看看有没有宝藏藏在里面!
上面两句话地区别在于,一个无目的,一个有目的
一个只是再房间里面转悠,一个在转悠地同时还要看看房间里面有没有宝藏
其实上面这两句话对应了DFS算法的两种基本类型
无目的的深度搜索——裸的DFS
有目的的深度搜索——一般的DFS
(1)无目的DFS就像你去亲戚家做客,主人带你在他家闲逛了解他家的布局
(2)有目的DFS就像土匪掠夺财产时在你家到处探寻,直到找到你的私人小金库!
但作为 算法 而言我们不能到处瞎转悠,有经验的主人和土匪往往也不会那么做!
我们需要一种高效的搜索方案,它能让我们在最短时间内完成搜索任务!
如何搜索?
DFS的关键要领在于——当下这一步干什么,然后下一步干什么。
这是所有DFS搜索🔍算法的核心
,我们只要知道当下和下一步的动作,就能通过递归连贯出整个搜索动作。
让我们来举个例子
题目:DFS - 选数
题目大意:求从N个数里面选出K个数出来并且使选出的数的和为素数的的可能性有几种?
假如:N=5,K=3
5个数为:1 2 3 4 5
我们要做的是挑出3个数出来然后计算求和并判断和是否为素数。
你可能已经想到怎么去选了,一般的选法如下:
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
略
我们要做的就是每一次选出一个数,首先仔细观察上述选数过程
当我们去选1 2 3时我们发现这是依次递增
的,我们不免想到用For循环
去实现这个选数过程,For循环每进行一次
就选入
一个数
可能你会这么写:
dfs(int i,int k,int n)//选入的数为i,选了k个数,要选n个数
{
if(k==n)
//略
for(int i=1;i<=n;i++)
dfs(i+1,k+1,n)
//略
}
但问题来了我们在1 2 3
选完之后是如何蹦到1 2 4
呢?
难不成我们需要再从头选一遍,标记3
已经被选过了,直接越过它
去选4
仔细思考你会发现这是一个无比繁琐
的工作,你需要灵活
的标记策略来应对不同的选数情况
我们想要的是不再从头去选,而是在选完1 2的基础上再去直接选4
所以我们需要一种方法来保留
选完1 2时的状态
可能DFS算法尚在研究<