zoukankan      html  css  js  c++  java
  • DFS 深度优先搜索

    DFS 深度优先搜索

    (准确来讲 应该是递归枚举与深度优先搜索)经过好一阵的刷题,意外的发现自己不会通过枚举的方法暴力使用dfs,莫慌,那就来复习一下。

     深度优先搜索

    就跟他的名字一样,所谓深度优先,就是尽可能(深)的搜索,其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。 Dfs通常用递归的方式来实现(如果对递归理解的还不是很深入,那你可以把他想象成一个栈)

     他的思想:

     访问当前点now,依次从now的未被访问的邻接点出发,对图进行深度优先遍历,直至图中和v有路径相通的顶点都被访问,.若此时图中尚有顶点未被访问,则从一个未被访问的顶点出发,重新进行深度优先遍历,直到图中所有顶点均被访问过为止。

    原理过程:

    A 把一个点压入栈中(根节点)

    B每次从栈中弹出一个元素,搜索所有在它下一级的元素,把这些元素压入栈中。并把这个元素记为它下一级元素的祖先

    C找到所要找的元素时结束程序

    D 如果遍历整个树还没有找到,结束程序

    <<举个例子

    1此时把A作为根节点放入栈中

    2从栈中取出A 寻找他的子节点B,C 并放入栈中

    3从栈中取出B寻找B的子节点D放入栈中

    4 重复以上操作……

    5走到节点F时,会发现F没有子节点,那么此时就会回跳到F的父节点,并寻找一个尚未走过的节点(若父节点没有尚未走过的子节点,则继续回跳)这个过程称之为回溯,一般如果一个点需要被多次搜索,那么为了保证答案的正确性在回溯的过程中需要把之前做的标记删掉

     因为递归的过程就是调用堆栈的过程,所以可以把dfs的过程抽象到递归

     1 void Dfs(int deep,……)
     2 {
     3    if(找到解了||走不下去了)
     4    { ……
     5        return ;
     6     }
     7     for(所有可能)
     8     {
     9        if(下一个状态合法)
    10        Dfs(deep+1,……)//枚举下一种情况(下一种状态or下一种深度)
    11        回溯
    12     }
    13 }

    个人觉得搜图是比别的dfs更好理解 更好实现 dfs主要难在对状态的定义,去找相邻的状态,去递归回溯,搜图就按照上面的思路走就可以了,所以在这就不举搜图的例子了

    下面先以生成1-n的全排列为例理解dfs的过程

    以1开头的数来看,

    1先进入栈中然后是2 3 4 ,

    此时n==cur 输出,最深处递归结束,弹出4 ,第四位无法选择,

    回到第三层,第三层递归结束 弹出3

    第三位可以选择4 第四位可以选择3,

    此时n==cur 输出,最深处递归结束 弹出3,第四位无法选择

    回到第三层,第三层递归结束 弹出4,第三位无法选择

    回到第二层,第二位可以选择3 第三位可以选择2

    第四位可以选择4

    以此类推……………………………………

    深度优先搜索算法的要点是 定义状态与当前状态和下一状态之间如何传递,找到边界条件,以及所有可能的范围,如何判断该状态是否合法,是否要回溯 回溯的条件

    有了框架结合题目修改程序,但都离不了这个过程

    深度优先搜索算法的优化

    一.缩小搜索范围
    缩小搜索范围一般可从两个方面考虑优化,

    第一是在递归前对尚待搜索的信息进行预处理,减少搜索量;

    第二是增加约束条件,使其在保证不遗漏解的前提下尽可能"苛刻"。

    二,改变搜索的次序
    如果要求问题的全部解,那么无论你怎样搜索,总是要将整棵树都搜索完才能得到所有的解,这时候无论怎样改变搜索的次序都是无济于事的.

    如果只要求问题的一个解而不是所有的问题,则通过改变搜索的次序会收到意想不到的效果。

    三,剪枝

    所谓剪枝,顾名思义,就是通过某种判断,避免一些不必要的遍历过程,形象的说,就是剪去了搜索树中的某些"枝条",故称剪枝

    剪枝作为搜索的优化工具,并不是盲目的,恰恰相反,剪枝有一些逻辑性与规律性的方法.剪枝条件的获取主要有两个方法:直觉法和推理法.
    ①直觉法:就是通过观察比较部分分枝的性状特征,表面现象等,得出归纳猜想后的剪枝条件.这种剪枝条件的获取很大程度上取决于编程人员的直觉,其实质上是一种不完全归纳法,其结论有一定的风险性,因此其正确性无法保证.此方法类似于那种贪心法.
    ②推理法:通过建立数学模型,把握问题的实质,并充分应用各种定理推论来演绎出一条剪枝条件.例如许多极值问题的求解,往往通过求解不等式约束上下限来剪枝.

    (“深度优先搜索算法的优化”部分摘自 <杜瑜皓-深度优先搜索解题报告>,另外,之前偶尔见到一次奇偶性剪枝,也引用到这里)

    也就是说当要走偶数步而规定的步数是奇数,或者要走奇数步而规定的步数是偶数,都是不可能到达的,如果要想到达,则要走的步数和规定的步数的奇偶性应该一致。又可知,奇偶性一致的两个数的差或者和都是偶数。

    奇偶性剪枝题目:http://acm.hdu.edu.cn/diy/contest_status.php?cid=1991

    祝大家今后题题AC!

     
  • 相关阅读:
    编译Android系统源码和内核源码
    Ubuntu中的解压缩文件的方式
    将秒数转换为基于00:00的时间
    git sshkeygen Fingerprint cannot be generated解决方法
    git bash下的选择、复制、粘贴
    mac 配置jdk maven
    自定义标签
    垃圾收集器和收集算法
    多线程并发中的同步
    现在有T1、T2、T3三个线程,怎样保证T2在T1执行完后执行,T3在T2执行完后执行?使用Join
  • 原文地址:https://www.cnblogs.com/YangKun-/p/12445925.html
Copyright © 2011-2022 走看看