精华内容
下载资源
问答
  • 递归回溯和迭代回溯
    2021-11-27 17:36:52

    递归回溯:

    private static void backtrack(int t){
        if t>=n then                          //递归深度t大于等于最大层次n,输出解向量x
            output(x)
        for j<-f(n,t) to g(n,t) do            //f(n,t)为子树的起始编号,g(n,t)为子树的终止编号
            x[t]<-value(i)                    //将当前拓展节点x[t]赋上所选子树的值
            if constraint(t)&&bound(t) then   //constraint(t)约束函数、bound(t)界函数
                backtrack(t+1)
    }

    迭代回溯:

    void iterativeBacktrack ()
    {
    	t=1;
    	while t>0 then
    		if f(n,t)<=g(n,t) then                //当前是否还有节点可选
    		    for i<-f(n,t) to g(n,t) do        //遍历所有节点
                    x[t]<-value(i)
    				if constraint(t)&&bound(t) then
    					if solution(t) then
                            output(x)
    					else
                            t++
    		else
                t--
    }

    更多相关内容
  • 回溯法之递归回溯和迭代回溯

    万次阅读 多人点赞 2017-07-11 19:30:41
    回溯法有通用解题法之称,它可以系统的搜索一个问题的所有解或者任意解。它在问题的解空间树中,按深度优先策略从根节点出发搜索解空间树,算法搜索至解空间树的任意一个结点时,先判断该节点如(子树)是否包含问题...

          回溯法有通用解题法之称,它可以系统的搜索一个问题的所有解或者任意解。它在问题的解空间树中,按深度优先策略从根节点出发搜索解空间树,算法搜索至解空间树的任意一个结点时,先判断该节点如(子树)是否包含问题的解,如果肯定不包含,则跳过对其子树的搜索,逐层向其根节点回溯。否则,则按照深度优先的策略搜索子树。
        当回溯到根,且根节点的所有子树都已被搜索遍才结束。这种以深度优先方式系统搜索问题解的算法称为回溯法,适用于解决组合数较大的问题。

        例如求集合{1,2,3}的子集问题的解空间树如下:


    图示0代表该元素不在子集中,1代表该元素在子集中,显然可以看到该集合共有8个子集,因此可以按照回溯法的思想搜索它所有的子集。

         回溯法搜索解空间树时,通常采用两种策略避免无效搜索,一种是用约束函数法在节点处剪去不符合要求的子树;第二种是用界限函数剪去得不到最有解的子树。

        

        回溯法一般有两种实现方式,分别是递归回溯和迭代回溯。
        递归回溯算法伪代码如下:
    void Backtrack(int t){
    	if(t > n) Output(x);//Output 记录或者输出可行解
    	else{
    		for( int i = f(n,t); i <= g(n,t); ++i){//f(n,t)和g(n,t)表示在当前结点未搜索过的子树的起始编号和终止编号
    			x[t] = h(i);
    			if(constraint(t) && Bound(t)) Backtrack(t+1);//constraint和bound分别是约束函数和界限函数
    		}
    	}
    }
        迭代回溯算法伪代码如下:
    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--;
     			}
     		}
     	}
     }
    
        最后贴上子集树(集合的所有子集)与排列树(求序列的所有排列)的递归算法和迭代算法:
        求序列全排列算法实现:
    /* 
        设R={r1,r2,...rn}是要进行排列的n个元素.Ri=R-{ri}.集合X中元素的全排列记为 
        Perm(X).(ri)Perm(X)表示在全排列Perm(X)的每一个排列前加上前缀ri得到的排列 
        R的全排列可归纳定义如下: 
            当n=1时,Perm(R)=(r),其中r是集合R中唯一的元素; 
            当r>1时,Perm(R)由(r1)Perm(r1),(r2)Perm(r2).....(rn)Perm(rn)构成. 
            依此递归定义,Perm(R)的递归算法如下: 
    */
    #include <iostream>
    #include <algorithm>
    #include <vector>
    using namespace std;
    int cnt = 0;
    void Perm(int list[],int k,int m){
      if(k == m){
        cnt++;
        cout<<"cnt = "<<cnt<<endl;
        for(int i = 0 ; i <= m ; i++){
          cout<<list[i]<<"  ";
        }
        cout<<endl;
      }
      else{
        for(int i = k ; i <= m; i++){
          swap(list[k],list[i]);
          Perm(list,k+1,m);
          swap(list[k],list[i]);
        }
      }
    
    }
    /*
    迭代实现,算法思想:
    该问题的解空间是一棵排列树(可以看作子集树剪去了很多枝)
    因此采用回溯法对解空间树进行搜索,得到想要的结果
    对于长度为N的序列,可以看作深度为N的一棵树,依次对每一层搜索其子树节点
    该例子中,第一层可选的子树节点有N个,第二层有N-1个知道最后一层叶子节点只有一个
    是一棵典型的排列树
    */
    void Perm_iterative(int list[],int n){
      int t = 0;
      vector<int> p = {-1,-1,-1,-1,-1};//p[i]表示在第i个位置(树第i层)排list[p[i]],list的第p[i]个元素
      //set<int> bkt[n+1];
      while(t >= 0){
        int k = p[t];
        while(find(p.begin(),p.end(),k) != p.end())  k++;
    
        if( k > n || t > n){//返回上一层节点时,清空子树状态
            for(int i = t; i <= n; ++i)  p[i] = -1;
            t--;
            continue;
        }
        p[t] = k;
        if( t >= n){//找到一个排列
            cnt++;
            cout<<"cnt = "<<cnt<<endl;
            for(int i = 0 ; i <= n ; i++){
              cout<<list[p[i]]<<"  ";
            }
            cout<<endl;
        }
        else{
            //cout<<"that"<<endl;
            t++;
        }
      }
      return;
    }
    
    int main(){
      int x[] = {1,2,3,4,5};
      cout<<"this is  a test"<<endl;
      //Perm(x,0,4);
      Perm_iterative(x,4);
    }

    求集合子集算法实现:
    /*
    问题描述:对于一组各不相同的数字,从中任意抽取1-n个数字,构成一个新的集合。
    求出所有的可能的集合。例如,对于集合{1,2,3},其所有子集为{1},{2},{3},{1,2},{1,3},{2,3}{1,2,3}, 
    给定一个数组(元素各不相同),求出数组的元素的所有非空组合(即数组的所有非空子集)
    解法:位向量法。用一个辅助数组表示各个元素的状态。1表示在集合中,0表示不在数组中。递归地求解所有的子集。
    算法描述如下://这里的算法对空集也输出了,可修改之使得只输出非空集合。
    下面代码分别用递归回溯和迭代回溯的方法实现了算法
    
    */
    
    #include <iostream>
    using namespace std;
    //递归实现
    void getSubset(int list[],bool v[],int a,int b){
      if(a == b){
        for(int i = 0; i < b; i++){
          if(v[i])
          cout<<list[i]<<"  ";
        }
        cout<<endl;
        return;
      }
      v[a] = true;
      getSubset(list,v,a+1,b);
      v[a] = false;
      getSubset(list,v,a+1,b);
    
    }
    //迭代实现
    void getSubset_iterative(int list[],int n){
      int t = 0;//t 代表解空间树的深度
      bool v[n+1] = {false,false,false,false};
      int init[n+1] = {0,0};
      while( t >= 0){
              if(2 > init[t]){
                init[t]++;
                v[t] = !v[t];
                if( t >= n ){
                  for(int i = 0; i <=n; i++){
                    if(v[i])  cout<<list[i]<<"  ";
                  }
                  cout<<endl;
                }
                else{
                  ++t;//进入下一层
                } 
              }
              else{
                //回溯至上一层,并将该层的状态重置,一定要重置
                init[t] = 0;
                --t;
              }    
      } 
    
    }
    int main(){
        int li[] = {1,2,3,4};
        bool v[] = { false,false,false,false};
        getSubset(li,v,0,4);
        getSubset_iterative(li,3);
    }
    


    两段代码coding.net地址: https://git.coding.net/Mansion/Backtrace_IterativeVSRecursive.git 


    展开全文
  • 迭代法的回溯分析:回溯法可以通过限界函数做剪枝处理。搜素的约束函数是总重量背包容量M.下面通过贪心算法确定限界函数,当前面k-1个物品已经做好装包决策,可能达到的最大效益值是该上界函数。// BackTrace_0_1...

    问题:0/1背包问题

    例子:weight数组代表物品重量,value数组代表物品价值,M代表背包容量。背包是按单位价值递减的顺序排列的,即value[i]/weight[i]>value[i-1]/weight[i-1].

    const int weight[Max]={1,11,21,23,33,43,45,55};const int value[Max]={11,21,31,33,43,53,55,65};intM=110;迭代法的回溯分析:回溯法可以通过限界函数做剪枝处理。搜素的约束函数是总重量<=背包容量M.下面通过贪心算法确定限界函数,当前面k-1个物品已经做好装包决策,可能达到的最大效益值是该上界函数。// BackTrace_0_1backpack.cpp : 定义控制台应用程序的入口点。

    //回溯法解决0/1背包问题;

    #include "stdafx.h"

    #include

    #include

    #include

    using namespace std;

    const int Max=8;

    const int weight[Max]={1,11,21,23,33,43,45,55};

    const int value[Max]={11,21,31,33,43,53,55,65};

    //如果搜素算法在求解该节点之前已经知道目前的最优解大于这个界值的效益,就没有必要接着搜素下去。

    //前k件物品是否装已经确定,还剩k+1,...,Max-1件未装

    double BoundF(int cp, int cw, int k, int M)

    {

    double b=cp, c=cw;

    int i;

    for(i=k+1;i BackKnap(int M,double & fp)

    {

    vector X(Max),Y(Max);

    int cw,cp,k;

    fp=-1;//当前搜素的最优解,初始时设为-1

    cw=cp=k=0;

    do{

    while(k=Max)

    {

    fp=cp;//

    k=Max-1;//搜索到一个当前最好的结果时,保存在X中

    for(int i=0;i=0&&Y[k]!=1)//回溯到第一个非零的节点

    k--;

    if(k<0) return X;//如果回溯到顶,说明已经遍历完所有结果

    //下面是已经找到了第一个Y[k]=1的节点,将其设为0,更新cw,cp.再从该节点开始往下搜索

    Y[k]=0;

    cw=cw-weight[k];

    cp=cp-value[k];

    }

    k++;

    }while(1);

    }

    void show(int i)

    {

    cout

    double fp;

    X=BackKnap(M,fp);

    for_each(X.begin(),X.end(),show);

    cout<

    a9ad58730a163e941acfbe3a7cf7ca5c.png递归的回溯没有考虑利用限界函数剪枝,仅根据约束条件遍历回溯。// Back_trace_0_1_backKnap.cpp : 定义控制台应用程序的入口点。

    //

    // BackTrace_0_1backpack.cpp : 定义控制台应用程序的入口点。

    //回溯法解决0/1背包问题;

    #include "stdafx.h"

    #include

    #include

    #include

    using namespace std;

    const int Max=8;

    const int weight[Max]={1,11,21,23,33,43,45,55};

    const int value[Max]={11,21,31,33,43,53,55,65};

    int M=110;//背包容量

    int bestp=-1;//最优解

    int bestx[Max];

    vector x(Max);

    // 已对前i-1个物品是否装入做好决策,对第i个物品装入的算法

    void Backtrack(int i,int cp, int cw)//cp,cw是当前的背包内物品的重量和价值

    {

    int j;

    if(i>=Max)//到达一个叶节点,说明得到一个可行解

    {

    if(cp>bestp)//如果这个解能达到更好的效益值,更新解的结果

    {

    bestp=cp;

    for(i=0;i

    8c5eb1299a7a453eafef3aace726f4b8.png

    展开全文
  • 递归在算法中很常见,比如下面两个例子。 A-program // 二叉树递归版本 visit(root){ if root==null; return visit(root.left) // 左树 visit(root) // 根 visit(root.right) // 右树 } 斐波那契数列的递归...

            递归在算法中很常见,比如下面两个例子。

    A-program
    // 二叉树中序递归版本
    visit(root){
        if root==null; return
        visit(root.left) // 左树
        print(root)  // 根
        visit(root.right) // 右树
    }
    

           sum(n)求和:

    B-program
    // 递归版本求和
    f(n){
        if n=1 ;return 1
        return n+f(n-1)
    }

           在算法设计中,递归由于调用栈过深,资源得不到释放,性能较差,往往需要转换为迭代版本,理论上,可以证明,迭代和递归是可以相互转换的。

            递归改迭代,是回溯算法的具体应用。在迭代版本中,我们很大可能会用到栈的数据结构,来以此模拟函数的调用过程。在迭代中,需要我们显示存储当前节点和路径。B是单路递归(尾递归),A是多路递归,B是A的一个特例。

            A迭代版本:

    visit(root){
        stack,root // 存储路径和当前节点
        // 有节点没有访问到或者回溯到
        while(stack.size()>0 || root !=null){
            while(root!=null){
                 stack.push(root)
                 root.left
            }
            // 没有左节点后就开始回溯
            cur = stack.pop()
            print(cur)
            
            root = cur.right
        }
    }

              B迭代版本:

    其实,最能体现回溯算法的威力例子就是树的遍历:preOrder,inOrder,postOrder三种遍历方法。

    ##回溯算法模板

    展开全文
  • 递归和回溯

    2019-05-09 19:59:00
    递归和回溯 递归 任何调用自身的函数称为递归递归的要点在于,递归函数调用自身去解决一个规模比原始问题要小一些的问题。 递归函数的格式 函数不在递归地情况称作基本情形(base case,也称基本情况)。 函数调用...
  • 如一共有4行4列,当进行到queen(4)时,函数结束递归,输出一个结果,删除栈顶元素(最后一行的位置)此时queen(4)执行完成,返回到调用她的地方,即判断第三行的(3,k),然后执行k++,继续寻找第三行后面的可行...
  • N皇后问题的递归回溯实现

    千次阅读 2014-04-24 10:55:50
    N皇后问题的递归回溯实现
  • 循环(迭代)与递归的区别 1.循环&迭代&回溯&递归&递推 循环:不断重复进行某一运算、操作。 迭代:不断对前一旧值运算得到新值直到达到精度。一般用于得到近似目标值,反复循环同一运算式(函数)...
  • n皇后问题(递归回溯迭代回溯

    千次阅读 2020-04-09 20:36:41
    递归回溯法 #include <iostream> #include <cstring> #include <cmath> using namespace std; int n,sum=0; int x[10000]; bool judge(int i) { for (int j=1;j<=i-1;j++) { if (abs(j - i...
  • 详解回溯

    千次阅读 多人点赞 2019-12-04 17:11:10
    文章目录回溯法概念适用条件解题步骤回溯DFS的区别常见题型素数环迭代递归 回溯法 references: 回溯算法 回溯算法 详细讲解回溯算法(一) 回溯法-素数环问题 素数环(java实现) 概念 回溯(backtracking)法是...
  • 今天就简单来谈谈这几者之间的关联区别递归一句话,我认为递归的本质就是将原问题拆分成具有相同性质的子问题。递归的特点:1、子问题拆分方程式,比如:f(n) = f(n-1) * n2、终...
  • 解0-1背包问题的回溯法与解装载问题的回溯法十分相似。 在搜索解空间树时,只要其左儿子结点是一个可行结点,搜索就进入其左子树。当右子树有可能包含最优解时才进入右子树搜索,否则将右子树剪去。设r是当前剩余...
  • 回溯法是一种算法思想,而递归是一种编程方法,回溯法可以用递归来实现。回溯法的整体思路是:搜索每一条路,每次回溯是对具体的一条路径而言的。对当前搜索路径下的的未探索区域进行搜索,则可能有
  • 实际上递归的代码更清晰,但是从学习的角度要理解递归真正发生的什么,是如何调用的,调用层次路线,调用堆栈中保存了什么,可能是不容易。但是不可否认递归的代码更简洁。 缺点:由于递归需要系统堆栈,所以空间...
  • N-Queens(递归回溯+迭代回溯)回溯法算法思想:  回溯法在问题的解空间树中,按深度优先策略,从根节点出发搜索解空间树;  算法搜索至解空间树的任一节点时,先判断该节点是否包含问题的解;  如果肯定不...
  • #回溯 A=['a','b','c'] res=[] def sons(n,t): res.append(t) for i in range(n,len(A)): sons(i+1,t+[A[i]]) sons(0,[]) print(res) #迭代 nums=['a','b','c'] res = [[]] ...迭代和递归回溯)的
  • java版迭代回溯算法和递归回溯算法上完回溯法的算法后,为了避免以后忘记了这些算法,自己实现了一遍,仅供大家学习参考,以下是代码:package ctong;import java.util.Random;public class NQueen {/*** ctong*///...
  • 回溯法是一种能解决百分之九十九的问题的一种通用的算法思想,在问题的解空间树中,按深度优先策略对整个解空间树进行搜索,当算法搜索到某一个节点如果不包含问题的解则会直接跳过对这个子树的搜索回溯到这个节点的...
  • 递归回溯

    千次阅读 2019-11-20 21:33:45
    递归回溯 一、递归回溯的区别 个人理解: 递归的定义: 递归是此时的状态会用用到...递归和迭代的区别: 递归: 遇到基本条件时会终止 每次递归都需要开辟帧栈耗费内存 如果无休止的递归下去会发生栈溢出...
  • 1.回溯法 有通用解题法之称,它可以系统的搜索一个问题的所有解或者任意解。它在问题的解空间树中,按深度优先策略从根节点出发搜索解空间树,算法搜索至解空间树的任意一个结点时,先判断该节点(如子树)是否包含...
  • 全都是自己写的,都能跑出来 实打实写的哦~ 仅供参考 最重要的还是自己理解 1.学习并掌握回溯法 2.利用迭代回溯和递归回溯两种方法解决01背包问题。 预览地址:
  • 循环:不断重复进行某一运算、操作。 示例:for 循环 递推:从初值出发反复进行某一运算得到...递归:从所需结果出发不断回溯前一运算直到回到初值再递推得到所需结果----从未知到已知,从大到小,再从小到大(你想进.
  • [python实现] 递归回溯(深度优先)构造随机迷宫_☆迷茫狗子的秘密基地☆-CSDN博客https://blog.csdn.net/qq_39391544/article/details/121306611 在上次的基础上稍加改动,可以更加直观地欣赏整个过程 美中不足的是...
  • 递归和迭代的区别

    2021-08-25 09:51:45
    递归和迭代的区别 一、递归 递归:重复调用函数自身实现循环称为递归**(A调用A)** 递归是一个树结构,从字面可以其理解为重复“递推”“回归”的过程,当“递推”到达底部时就会开始“回归”,其过程相当于树的...
  •   以2019蓝桥杯C/C++B组的两个题目为例,来进行说明回溯法的递归和迭代版本 作为篮球队教练,你需要从以下名单中选出 1 号位至 5 号位各一名球员, 组成球队的首发阵容。 每位球员担任 1 号位至 5 号位时的评分...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 13,591
精华内容 5,436
关键字:

递归回溯和迭代回溯