DFS算法入门之排列组合

您所在的位置:网站首页 c和a哪个是排列哪个是组合图形 DFS算法入门之排列组合

DFS算法入门之排列组合

2024-07-16 15:46| 来源: 网络整理| 查看: 265

(本文用于帮助初学者入门dfs算法,碍于笔者本人实力,对更深的无涉及,请原谅。)

算法介绍

一种用于遍历或搜索树或图的算法。 沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过或者在搜寻时结点不满足条件,搜索将回溯到发现节点v的那条边的起始节点。整个进程反复进行直到所有节点都被访问为止。属于盲目搜索,最糟糕的情况算法时间复杂度为O(!n)。

算法基本思想 回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。 算法过程 这种算法在每一步中优先考虑深度较浅的分支,也就是说,它总是优先探索深度优先的路径。

深度优先搜索的过程可以大致分为几个步骤:

初始化:首先对问题进行初始化,确定初始状态。选择当前节点:选择当前节点作为初始节点。扩展当前节点:将当前节点的所有子节点展开,将其子节点添加到待探索列表中。重复步骤3和4,直到所有节点都被展开。

模板 void dfs(int step) { 判断边界 { 相应操作 } 尝试每一种可能 { if(满足条件) { 标记 继续下一步dfs(step+1) 恢复初始状态(回溯的时候要用到) } } }

回溯与剪枝

在DFS算法中,回溯是一个关键的概念。当算法发现当前路径不能达到目标或者已经探索完所有可能的分支时,它会回溯到上一个节点,尝试其他的路径。这种方法确保了算法能够找到所有可能的解决方案。

剪枝是一种优化技术,它通过提前排除那些不可能达到目标的路径来减少搜索空间。在全排列问题中,如果一个数字已经被选择,那么在当前的排列中就不需要再考虑它,这实际上是一种剪枝操作,可以避免无效的搜索和重复的排列

问题

排列

和组合、切割、子集问题最大区别是,排列问题for循环不需要记录索引,每次递归从0开始,因为排列有序,[1,2]和[2,1]是两个集合。 一个元素在一个排列中只能使用一次,因此需要数组记录哪些元素使用过。 去重,一个排列元素不重复,首先对数组进行排序,使重复元素挨在一起

然后保存节点、递归、回溯,然后回溯时,如果同一层分支中存在重复元素,则跳过,注意递归时的起始位置,从0开始

P1706 全排列问题

在这里插入图片描述

思路:

利用深搜的思想:

对于给定的序列,刚开始时我们知道序列的第一个元素,剩余的序列元素此时又可以看成是一个全排列的例子;我们可以对剩余的序列进行与开始相同的操作,直到中只一个元素为止。这样我们就获得了所有的可能性。因此不难看出这是一个递归的过程。

分析可知我们要知道目前为止已经选了几个数(范围是1 到 n);

所以我们的递归函数可以含有该参数,

即 dfs(int x) 其中 x表示的是其中一种情况的第几个数

还需要知道跳出递归的条件:当选到 n 个数的时候,也就是这一组数已经选完了,就 return。

核心代码

在函数内部,首先判断是否已经找到了n个数字,即是否满足题目要求的组合长度。如果满足条件,则输出当前组合的结果。

如果没有找到足够的数字,则进入循环,遍历数组a中的所有元素。对于每个元素,检查其是否已经被选中(标记为1)。如果没有被选中,则将其赋值给答案数组d的第x个位置,并将对应的标记设置为1。然后递归调用dfs函数,将x加1,继续寻找下一个数字。

在递归调用返回后,需要将标记c[i]重新设置为0,以清除该数字在该位置的结果。这是回溯的过程,确保每次递归调用都能恢复到原始状态,以便尝试其他可能的组合。

void dfs(int x)//x表示的是其中一种情况选好的第几个数 { if(x==n)//说明该情况所需要的数都已经找到 { for(int v=0;v


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3