zoukankan      html  css  js  c++  java
  • 2018.4.24 回溯法

    为了描述问题的某一状态,必须用到该状态的上一状态,而描述上一状态,又必须用到上一状态的上一状态……这种用自已来定义自己的方法,称为递归。

    从问题的某一种可能出发, 搜索从这种情况出发所能达到的所有可能, 当这一条路走到” 尽头 “的时候, 再倒回出发点, 从另一个可能出发, 继续搜索. 这种不断” 回溯 “寻找解的方法, 称为回溯。

    回溯法是以深度优先方式系统搜索问题解的算法,适用于解决组合数较大的问题。

    回溯就是让计算机自动的去搜索,碰到符合的情况就结束或者保存起来,在一条路径上走到尽头也不能找出解,就回到原来的岔路口,选择一条以前没有走过的路继续探测,直到找到解或者走完所有路径为止。

    回溯就是一种试探,类似于穷举,但回溯有“剪枝”功能。

    回溯法一般有两种实现方式,分别是递归回溯和迭代回溯。

    回溯一般使用递归来实现,那个这个递归调用该如何来写呢?进行回溯搜索都会有一系列的步骤,每一步都会进行一些查找。而每一步的情况除了输入会不一样之外,其他的情况都是一致的。这就刚好满足了递归调用的需求。通过把递归结束的条件设置到搜索的最后一步,就可以借用递归的特性来回溯了。

    回溯常用模板:

    1.非递归模板:

       1: int a[n],i;
       2: 初始化数组a[];
       3: i = 1;
       4: while (i>0(有路可走)   and  (未达到目标))  // 还未回溯到头
       5: {
       6:     if(i > n)                                              // 搜索到叶结点
       7:     {   
       8:           搜索到一个解,输出;
       9:     }
      10:     else                                                   // 处理第i个元素
      11:     { 
      12:           a[i]第一个可能的值;
      13:           while(a[i]在不满足约束条件且在搜索空间内)
      14:           {
      15:               a[i]下一个可能的值;
      16:           }
      17:           if(a[i]在搜索空间内)
      18:          {
      19:               标识占用的资源;
      20:               i = i+1;                              // 扩展下一个结点
      21:          }
      22:          else 
      23:          {
      24:               清理所占的状态空间;            // 回溯
      25:               i = i –1; 
      26:          }
      27: }

    2.递归模板:

    1: int a[n];
       2: try(int i)
       3: {
       4:     if(i>n)
       5:        输出结果;
       6:     else
       7:     {
       8:         for(j = 下界; j <= 上界; j=j+1)  // 枚举i所有可能的路径
       9:         {
      10:             if(fun(j))                 // 满足限界函数和约束条件
      11:              {
      12:                   a[i] = j;
      13:                   ...                         // 其他操作
      14:                   try(i+1);
      15:                   回溯前的清理工作(如a[i]置空值等);
      16:              }
      17:         }
      18:      }
      19: }

    3.迭代回溯伪代码:

    void IterativeBacktrack(void){
         int t = 1;
         while(t > 0){
             if(f(n,t) < g(n,t)){
                 for(int i = f(n,t); i <= g(n,t); ++i){//这个for 是遍历各个值的意思,实际中写成for循环会有逻辑错误
                     x[t] = h(i);
                     if(constraint(t) && bound(t)){
                         if(solution(t)) Output(x);//solution 判断是否已经得到问题的解
                         else t++;
                     }
                     else t--;
                 }
             }
         }
     }

    4.递归回溯伪代码:

    void Backtrack(int t){
        if(t > n) 
            Output(x);//Output 记录或者输出可行解
        else{
            //f(n,t)和g(n,t)表示在当前结点未搜索过的子树的起始编号和终止编号
            for( int i = f(n,t); i <= g(n,t); ++i){
                x[t] = h(i);
                //constraint和bound分别是约束函数和界限函数
                if(constraint(t) && Bound(t)) 
                    Backtrack(t+1);
            }
        }
    }
    一边喊着救命,一边享受沉沦。
  • 相关阅读:
    Exchange 2013与 Office Web Apps 整合
    SharePoint2013 以其他用户登录和修改AD域用户密码 功能
    sharepoint 2010 自定义页面布局
    sharepoint 2010 记录管理 对象模型
    SharePoint2010 对象模型 关联列表
    在SharePoint Server 2010中更改“我的网站”
    xenapp 6.5 客户端插件第一次安装总是跳到官网
    如何解决在Windows Server 2008 R2 上安装证书服务重启后出现 CertificationAuthority 91错误事件
    在Win7 Hyper-v虚拟机中挂接真实机的声卡
    win8 中如何删除 共享文件夹 用户名和密码
  • 原文地址:https://www.cnblogs.com/fast-walking/p/8930343.html
Copyright © 2011-2022 走看看