DFS算法的本质
Posted 桃花涣小鱼干
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DFS算法的本质相关的知识,希望对你有一定的参考价值。
DFS算法的本质
引言
DFS 俗称深搜,是一种常见的算法模型
我们通过借助函数递归和递归停止条件的运用实现对数据的高级枚举
对于DFS算法而言,最重要的是如何去枚举数据,即如何去搜索?
这是在运用DFS之前我们就应该思考的问题,只有对其思考清楚,才不妨碍我们下一步去运用代码实现DFS!
OK! 让我们开始吧!
何为搜索?
让我们先忘记你学过DFS算法这件事,抛开脑子中具体的代码结构,单纯地以一个自然人地角度去思考,什么是搜索?
单独思考一个词汇可能我们不会获得很多,下面我们借助具体例子来说明:
假如我说——我们去搜索一间房子,你会想到什么?
寻找?探索?还是在房子里面转悠?
可能这么说会引起歧义,这里我们再具体一点
换成——我们去搜索这间房子,看看有没有宝藏藏在里面!
上面两句话地区别在于,一个无目的,一个有目的
一个只是再房间里面转悠,一个在转悠地同时还要看看房间里面有没有宝藏
其实上面这两句话对应了DFS算法的两种基本类型
无目的的深度搜索——裸的DFS
有目的的深度搜索——一般的DFS
(1)无目的DFS就像你去亲戚家做客,主人带你在他家闲逛了解他家的布局
(2)有目的DFS就像土匪掠夺财产时在你家到处探寻,直到找到你的私人小金库!
但作为 算法 而言我们不能到处瞎转悠或到处探寻
有经验的主人和土匪往往也不会那莫做!
我们需要一种高效的搜索方案,它能让我们在最短时间内完成搜索任务
接下来就是如何去搜索?
如何搜索?
DFS的关键要领在于——当下这一步干什么,然后下一步干什么。
这是所有DFS搜索🔍算法的核心
,我们只要知道当下和下一步的动作,就能通过递归连贯出整个搜索动作。
让我们来举个例子
DFS - 选数
题目大意:求从N个数里面选出K个数出来并且使选出的数的和为素数的的可能性有几种?
假如:N5,K3
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循环去实现这个过程
可能你会这么写:
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算法尚在研究
时人们就发现了,他们需要保留
一些状态,再去确定下一步的状态
巧妙的是函数递归
在设计时就拥有保留中断线程
的能力,在选数时我们可以完全用函数递归
来写
这样写的好处在于,每一层函数选着一个数,选着完后就像线路
一样被保存下来
最简单的我们选完1
,1的状态
就被保存下来了,我们要在1后面
选数时,只需要return返回到选完1
时的状态即可,这样我们可以顺利地选出
1 2
1 3
1 4
当前两个
数选完后,也就保存了选完两个数
的状态
其实我们可以用结点
去理解这个过程
最开始我们选择了1这个结点
,然后我们就可以连接2/3/4这三个结点
假如我们连接了1和2结点
就形成了1-2
的线路
,当我么们再往下DFS选数时,1-2
这条线路会被保存
下来,通过选数
和不断return返回到1-2这条线路的末尾,我们选出了:
1 2 3
1 2 4
1 2 5
核心代码如下:
void dfs(int x,int m,int sum,int k,int n)
{
if (m == k)
{
if (isPrime(sum))
ans++;
return;
}
for (int i = x; i < n; i++)
dfs(i+1,m + 1, sum + *(p + i), k, n);//i+1而非x+1
return;
}
部分过程如下:
1 //选1结点
1-2 //保留1结点选2结点
1-2-3 //保留1-2线路选3结点
1-2 //返回到1-2线路的末尾
1-2-4 //在已保留1-2线路后选4结点
1-2 //返回到1-2线路的末尾
1-2-5 //以此类推!!!
1-2
1
1-3
1-3-4
1-3
1-3-5
1-3
1
这也是为什么
你所见到的DFS算法
都拥有递归调用
的原因
DFS算法本就是依托于函数递归
而设计的一种高级枚举算法
感谢阅读!
END
以上是关于DFS算法的本质的主要内容,如果未能解决你的问题,请参考以下文章