回溯、递归、DFS方法

转自:https://www.cnblogs.com/steven_oyj/archive/2010/05/22/1741376.html1.

1.回溯解法框架

我觉得这个递归方法更好理解,迭代的方法我没太看懂。

   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: }

以非常典型的,leetcode22题,生成括号为例:

class Solution(object):
    def generateParenthesis(self, N):
        ans = []
        def backtrack(S = ‘‘, left = 0, right = 0):
            if len(S) == 2 * N: #给出解空间
                ans.append(S)
                return
            if left < N:#这两个if判断都是剪枝
                backtrack(S+‘(‘, left+1, right) #扩展搜索节点
            if right < left:#这里是关键
                backtrack(S+‘)‘, left, right+1)

        backtrack()
        return ans

(1)针对所给问题,确定问题的解空间:

首先应明确定义问题的解空间,问题的解空间应至少包含问题的一个(最优)解。 (对应if判断解)

(2)确定结点的扩展搜索规则    (确定往下搜索调用)

(3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。(if判断递归调用条件)

https://leetcode.com/articles/letter-combinations-of-a-phone-number/ 就像这道题,它只是一个简单的深度优先遍历然后得到所有的解,我觉得它关键是没有剪枝和回去的过程,只是遍历到最深的节点,然后返回了。

2.DFS和回溯的关系

https://www.1point3acres.com/bbs/thread-137584-1-1.html这个讲的挺好的。

特点:就是recursive call之后要退回到之前的一个状态。

回溯是DFS的一种,是它的子集。

回溯不保留树结构,也就是剪枝的意思。

定义:https://stackoverflow.com/questions/1294720/whats-the-difference-between-backtracking-and-depth-first-search

回溯是一种更通用的算法。

深度优先搜索是与搜索树结构相关的回溯的一种特定形式。

3.递归和回溯

https://blog.csdn.net/fengchi863/article/details/80086915 这个补充的也挺好的。

  • 递归是一种算法结构,回溯是一种算法思想。
  • 一个递归就是在函数中调用函数本身来解决问题。
  • 回溯就是通过不同的尝试来生成问题的解,有点类似于穷举,但是和穷举不同的是回溯会“剪枝”。

递归的一般过程:

void f()
{
     if(符合边界条件)
     {
        ///////
        return;
     }  

     //某种形式的调用
     f();
}  

回溯的一般过程:

void DFS(int 当前状态)
{
      if(当前状态为边界状态)
      {
        记录或输出
        return;
      }
      for(i=0;i<n;i++)       //横向遍历解答树所有子节点
      {
           //扩展出一个子状态。
           修改了全局变量
           if(子状态满足约束条件)
            {
              dfs(子状态)
           }
            恢复全局变量//回溯部分
      }
}  

BFS和DFS相似。BFS显式用队列,DFS隐式用栈,即递归。

原文地址:https://www.cnblogs.com/BlueBlueSea/p/12494908.html

时间: 2024-10-14 07:48:35

回溯、递归、DFS方法的相关文章

递归,回溯,DFS,BFS的理解和模板【摘】

递归:就是出现这种情况的代码: (或者说是用到了栈) 解答树角度:在dfs遍历一棵解答树 优点:结构简洁缺点:效率低,可能栈溢出 递归的一般结构: 1 void f() { 2 if(符合边界条件) { 3 /////// 4 return; 5 } 6 7 //某种形式的调用 8 f(); 9 } 回溯:递归的一种,或者说是通过递归这种代码结构来实现回溯这个目的.回溯法可以被认为是一个有过剪枝的DFS过程.解答树角度:带回溯的dfs遍历一棵解答树回溯的一般结构: 1 void dfs(int

组合的输出(回溯、dfs)

问题 O: [回溯法]组合的输出 题目描述 排列与组合是常用的数学方法,其中组合就是从n个元素中抽出r个元素(不分顺序且r<=n),我们可以简单地将n个元素理解为自然数1,2,…,n,从中任取r个数. 现要求你不用递归的方法输出所有组合. 例如n=5,r=3,所有组合为:     l 2 3    l 2 4    1 2 5    l 3 4    l 3 5    1 4 5    2 3 4    2 3 5    2 4 5    3 4 5 输入 一行两个自然数n.r(1<n<

再谈循环&amp;迭代&amp;回溯&amp;递归&amp;递推这些基本概念

循环:不断重复进行某一运算.操作. 迭代:不断对前一旧值运算得到新值直到达到精度.一般用于得到近似目标值,反复循环同一运算式(函数),并且总是把前一 次运算结果反代会运算式进行下一次运算 递推:从初值出发反复进行某一运算得到所需结果.-----从已知到未知,从小到达(比如每年长高9cm,20年180,30后270) 回溯:递归时经历的一个过程. 递归:从所需结果出发不断回溯前一运算直到回到初值再递推得到所需结果----从未知到已知,从大到小,再从小到大(你想进bat,那么编程就的牛逼,就得卸载玩

用递归和非递归的方法输出斐波那契数列的第n个元素(C语言实现)

费波那契数列(意大利语:Successione di Fibonacci),又译为费波拿契数.斐波那契数列.费氏数列.黄金分割数列. 在数学上,费波那契数列是以递归的方法来定义: {\displaystyle F_{0}=0} {\displaystyle F_{1}=1} {\displaystyle F_{n}=F_{n-1}+F_{n-2}}(n≧2) 用文字来说,就是费波那契数列由0和1开始,之后的费波那契系数就是由之前的两数相加而得出.首几个费波那契系数是: 0, 1, 1, 2, 3

std::sort 学习:一种递归分治方法

// std::sort 学习:一种递归分治方法 今天看了看 stl 的 std::sort 的代码,众所周知,这个函数是在快速排序递归太深的时候使用堆排序防止过度退化,但是今天说的不是这个.我们只看快速排序的部分. 我们一般实现快速排序大概是这样的(本王随意写了个用下标当参数的排序函数,领会意思即可). void quick_sort(int first, int last) // 某个数组的 [first, last) {  if ((last - first) > 1) {  int mi

非递归的方法遍历二叉树

//非递归遍历一棵树 需要借助栈 #include<stdio.h> #include<stdlib.h> struct Tree { int nValue; Tree *pLeft; Tree *pRight; }; struct Stack { Tree *root; Stack *pNext; }; Stack *pStack = NULL; void push(Tree *root) { Stack *temp = (Stack*)malloc(sizeof(Stack))

用递归和非递归的方法求解n的k次方

递归的方法 #include<stdio.h> int my_power(int n,int k) { if (k-- > 1) n*=my_power(n, k); return n; } int main() { int n = 0, k = 0, ret = 0; scanf("%d%d", &n, &k); ret = my_power(n, k); printf("%d^%d=%d\n", n, k, ret); syst

消除递归的方法

1.若递归是尾递归,那利用循环就可以消除,尾递归是是在函数末尾递归调用本函数的方式,满足以下格式: int function(int n){ if(n==0) return 1; else return function(n-1); } 尾递归采用循环,利用n=1的结果,定义一个变量记res记住,然后循环慢慢算n=2.3....的结果,每次计算出n的值后都让res记住,每次计算function的值利用res计算,下面给出计算一个例子 #include <stdio.h> //递归的方法 int

验证LeetCode Surrounded Regions 包围区域的DFS方法

在LeetCode中的Surrounded Regions 包围区域这道题中,我们发现用DFS方法中的最后一个条件必须是j > 1,如下面的红色字体所示,如果写成j > 0的话无法通过OJ,一直百思不得其解其中的原因,直到有网友告诉我说他验证了最后一个大集合在本地机子上可以通过,那么我也来验证看看吧. class Solution { public: void solve(vector<vector<char> >& board) { for (int i =