• 回溯法(复习笔记一)


    目录

    前言

    回溯法引入:

    一、回溯法

    二、实例分析

    数字组合问题

    三、基本步骤

    回溯法的基本步骤:

    剪枝的正确性:

    ※重点提醒

    四、深度剖析

    递归算法:

    非递归算法:

    总结


    前言

    回溯法引入:

    搜索法是解决问题时常用的方法,最笨的办法是穷举搜索,对于有些问题穷举搜索可以有效的解决,但是对于复杂问题穷举搜索法就不能很好地解决了。因此,在穷举搜索的基础上,提出了一些启发式的搜索方法。        

    回溯法的本质就是搜索,但是其搜索过程采用了一些“剪枝”的策略,可以一定程度上提高搜索的效率。回溯法也称为试探法,该方法在搜索过程中会向前试探搜索,也会在当前搜索路径走不通时,向后回溯。


    一、回溯法

    适用回溯法求解的问题            

    可用回溯法求解的问题P,通常要能表达为:  

    ⭐ 对于已知的由n元组(x1,x2,…,xn)组成的一个状态空间E={(x1,x2,…,xn)∣xi∈Si ,i=1,2,…,n},状态空间E成为问题的解空间;

    ⭐   给定关于n元组中的一个分量的一个约束集D,要求E中满足D的全部约束条件的所有n元组。其中Si是分量xi的定义域,且 |Si| 有限,i=1,2,…,n。

    ⭐   我们称E中满足D的全部约束条件的任一n元组为问题P的一个解。    

    ⭐注意,同一问题的解空间可能会有多种定义方式,要选择更简单,效率更高的方式。

    二、实例分析

    数字组合问题

    问题描述:找出从自然数1、2、……、n中任取r个数的所有组合。

      例如n=5,r=3的所有组合为:  

      (1) 1、2、3    (2) 1、2、4     (3) 1、2、5 (4) 1、3、4    (5) 1、3、5    

      (6) 1、4、5 (7) 2、3、4    (8) 2、3、5     (9) 2、4、5 (10) 3、4、5

      则该问题的状态空间为: E={(x1,x2,x3)∣xi∈S ,i=1,2,3 }  

      其中:S={1,2,3,4,5}    约束集为:   x1

    三、基本步骤

    回溯法基本步骤:

    (1)针对所给问题,定义问题的解空间;

    (2)确定易于搜索的解空间结构;

    (3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。

    常用剪枝函数

    用约束函数在扩展结点处剪去不满足约束的子树;

    用目标函数剪去得不到最优解的子树。(优化问题)

    剪枝的正确性:

    ●    对于许多问题,所给定的约束集D具有完备性,即i元组(x1,x2,…,xi)满足D中仅涉及到x1,x2,…,xi的所有约束意味着j(j

    ●   换句话说,只要存在0≤j≤n-1,使得(x1,x2,…, xj)违反D中仅涉及到x1,x2,…,xj的约束之一,则以(x1,x2,…,xj)为前缀的任何n元组(x1,x2,…,xj,xj+1,…,xn)一定也违反D中仅涉及到x1,x2,…,xi的一个约束,n≥i>j。

    ●    因此,对于约束集D具有完备性的问题P,一旦检测断定某个j元组(x1,x2,…,xj)违反D中仅涉及x1,x2,…,xj的一个约束,就可以肯定,以(x1,x2,…,xj)为前缀的任何n元组(x1,x2,…,xj,xj+1,…,xn)都不会是问题P的解,因而就不必去搜索它们、检测它们。

    ●   回溯法正是针对这类问题,利用这类问题的上述性质而提出来的比枚举法效率更高的算法。

    ※重点提醒

    •   回溯法在用来求问题的所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束。
    •   回溯法在用来求问题的任一解时,只要搜索到问题的一个解就可以结束。  
    •   回溯法在用来求问题的最优解时,要回溯到根,且根结点的所有子树都已被搜索遍,保留问题的目标函数值最优的解。

      回溯算法中用到的几个概念:            

    1.  如果已经搜索到的结点全部满足问题的约束条件,但搜索还没有到达空间树的叶子节点,则称为部分解
    2.  如果从根到当前节点的路径对应于问题的一个合法解,过程就终止(除非问题没有解)。      
    3.  如果这条路径的长度小于n,并且相应的解是部分的,那么就生成现节点的一个子节点,并将它标记为现节点(活节点)。        
    4. 如果对应的路径不是部分的,那么现节点标识为死节点。        
    5. 回溯算法有递归形式和非递归形式两种。

    四、深度剖析

    问题描述:        

    找出从自然数1、2、……、n中任取r个数的所有组合。

    问题的状态空间为  E={(x1,x2,...,xr)∣xi∈S ,i=1,2,...,r }        

    其中: S={1,2,3,...,n}       约束集为:   x1

    递归算法:
    1. INPUT: n个数分别为{12,…n},r。
    2. OUTPUT: n个数的所有r组合。
    3. 1. for k =1 to r
    4. 2. c[k] =0
    5. 3. end for
    6. 4. k =1
    7. 5. while k≥1
    8. 6. while c[k]≤n-1
    9. 7. c[k] =c[k]+1
    10. 8. if c为合法的 then得到一个r组合,输出c数组
    11. 9. else if c是部分解 then k =k+1
    12. 10. end while
    13. 11. c[k] =0
    14. 12. k =k-1
    15. 13. end while
    非递归算法
    1. INPUT: n个数分别为{12,…n},r。
    2. OUTPUT: n个数的所有r组合。
    3. 1. for k =1 to r
    4. 2. c[k] =0
    5. 3. end for
    6. 4. k =1
    7. 5. while k≥1
    8. 6. while c[k]≤n-1
    9. 7. c[k] =c[k]+1
    10. 8. if c为合法的 then得到一个r组合,输出c数组
    11. 9. else if c是部分解 then k =k+1
    12. 10. end while
    13. 11. c[k] =0
    14. 12. k =k-1
    15. 13. end while

    总结

     这两个算法的复杂性在最坏情况下生成了O(nr)个节点。对于每个生成的节点,如果当前解是合法的、部分的,或者两者都不是,这需要O(r)的工作来检查。因此,最坏情况下,全部的运行时间是O(rnr)

  • 相关阅读:
    自媒体人一般会从哪里找素材呢?
    解决爬虫在重定向(Redirect)情况下,URL没有变化的方法
    I2C,UART,SPI(STM32、51单片机)
    Jsoup抓取Https出现unable to find valid certification path to requested target
    【无标题】std::thread
    Linux scriptreplay回放你的高光时刻
    Java-Scanner用法
    Django(九、choices参数的使用、多对多表的三种创建方式、Ajax技术)
    SSE代替轮询?
    【探索Linux】—— 强大的命令行工具 P.15(进程间通信 —— system V共享内存)
  • 原文地址:https://blog.csdn.net/2301_79582459/article/details/139379992