回溯法基本知识

一、回溯法的描述

    从问题的某一种初始状态出发,依次搜寻每一种可能到达的情况,当走到这条路的“尽头”时,回过头到上一个情况,看这个情况是否还有没有走过的路,依次进行下去,直到遍历完所有的情况。

    回溯法实际上是一种深度优先搜索的方式。

 

二、算法框架

    对于回溯法解决的问题,通常将其解空间组织成图或者树的形式。

    例如,对于0-1背包问题。(通常的背包问题有两种:0-1背包和背包问题,前者亦可采取动态规划解决,后者可采用贪心策略。)

    给定n个物品,一个容量为w的背包,每个物品由重量wi和价值vi描述(i = 1 .....n),每个物品可以选择放入或不放入背包,试求最佳方案:充分(不要求全部)利用背包的容量,尽可能装入总价值量大的物品。

   当n = 3时,其解空间可由2^3个长度为3的有序序列组成:

    {(0,0,0),(0,0,1),(0,1,0),(0,1,1),(1,0,0),(1,0,1),(1,1,0),(1,1,1)}其中,0表示不装入,1表示装入。

    上述解空间可以利用如下图所示的完全二叉树表示:       

    此时,我们从结点A出发,以深度优先搜索(dfs)的方式搜索整个解空间。向下纵深一层,到达B结点,此时的B和前一时刻的A具有等同地位,依次向下纵深,当到达死结点,比如由A→B→D→H时,发现H已经无法纵深,将此种情况(0,0,0)的解作为一个参考解(并非最优值,甚至可能不成立),然后由H “回溯”至D结点,从D出发到达I,发现后面“无路可走”,再回溯至D,发现没有还没走过的路,再“回溯”至B,依次循环,直至遍历完所有结点。

    但是,在实际情况中,并不如上一段叙述的那样,会将整个解空间的所有点都遍历一遍,我们会遇到某些真正的“死结点”,即如果取了这个结点,将不会有可行解。

    举例说明:n = 3 ,w={16,15,15},v={45,25,25}  容量C = 30 ;

    开始时,从A出发,如果选择到B,此时C = 30 ,W = 0 ,现在可供选择的是D和E,如果选择D,则C  = 30 ,W=0,再有H和I可供选择,如果选择I,则C = 15 , W = 25,由于I是一个死结点,记录此时的W和C回溯至D,D此时还可以选择H…… 以上是可以直达叶子结点的路径,我们需要记录下在这种情况下的结果,以供最后比较哪一个是最优解。

   若从A出发时,到达C,则此时剩下容量C = 14 ,W = 45 ,此时从C出发可以到F和G,但是由于到达G需要15个容量,我们只剩下14个容量,因此G不可选,而F不需要容量,所以到达F,同理此时不能到M,只能到L,记下此时的结果(1,0,0),从L回溯至F,F没有可以走下去的路了,回到C,C也没有可以走下去的路了,回到A……

    再上述第二种遍历过程中,我们并没有遍历所有的结点,事实上,这是必须的。因为当设计到很大的n时,如果全部遍历的话在时间上的消耗是相当大的,我们写程序,不仅要追求正确求解,而且要追求高效求解。这种避免无效搜索的方法在八皇后问题中得到很充分的验证。

    避免无效搜索的方法通常有两种:

    (1)、用约束函数在当前结点处剪去不满足约束的子树

    (2)、用剪枝函数剪去得不到最优解的子树

    综上所述,运用回溯法解决问题的步骤可归纳如下:

    (1)、定义解空间

    (2)、确定解空间结构

    (3)、深度优先搜索解空间,并在此过程中避免无效搜索

    (4)、比较所得的各个可行解,得出最优解或根据题目要去输出可行解的个数

 

三、递归回溯代码实现

    对解空间深度优先搜索,要用到递归的方式,简易代码形式如下:

 

void backtrace(int t)
{
    if(t>n)
      do(记录或输出可行解)
    else
      for(i = 下界; i <= 上界 ; i ++)
      {
          x[t] = h[i];
          if(满足限界函数和约束条件)
            backtrace(t+1);
      }
}


    其中,t是递归深度;n是深度控制;

    当t > n 时,比如在0-1背包中,当t=4,到达第4层时,已经搜索至叶子结点了,此时记录或输出可行解即可。

    当t <= n 时,在该结点还有上界-下界+1个子结点,依次对这么多个结点进行搜索,如果不是死结点,即满足限界函数和约束条件,对其进行深度加1的回溯操作。

 

PS:在第一篇CSDN的文章,今天训练讲了回溯、深度优先搜索、广度优先搜索,发现有很多自己不懂的问题,很多OJ上的题目根本无从下手,算法导论书上讲的又太高深了,写这篇文章主要是希望让自己对回溯的整个基本概念和过程有个初步深刻的了解,写的比较啰嗦。下一篇文章记八皇后问题。

学习资料:C语言程序设计 曹计昌 科学出版社

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值