首页 > 编程语言 >5.1 回溯法的算法框架

5.1 回溯法的算法框架

时间:2024-04-05 11:04:26浏览次数:28  
标签:5.1 递归 问题 算法 搜索 回溯 空间 节点

 

第5章 回溯法

回溯法,作为一种高效的搜索算法,以其深度优先的搜索策略和高效的问题求解能力在算法设计和问题解决中占有重要地位。本章旨在深入探讨回溯法的原理、算法框架及其应用,帮助读者系统地理解和掌握回溯法。

学习要点

  • 理解回溯法的深度优先搜索策略。
  • 掌握回溯法解题的基本框架,包括:
    1. 递归回溯
    2. 迭代回溯
    3. 子集树算法框架
    4. 排列树算法框架
  • 通过具体的应用案例,学习回溯法的设计策略,包括但不限于:
    1. 装载问题
    2. 批处理作业调度
    3. 符号三角形问题
    4. N后问题
    5. 0-1背包问题
    6. 最大团问题
    7. 图的m着色问题
    8. 旅行售货员问题
    9. 圆排列问题
    10. 电路板排列问题
    11. 连续邮资问题

回溯法概述

回溯法被誉为“通用的解题方法”,能够系统地搜索问题的所有解或找到问题的一个解。它是一个既具有系统性又具有跳跃性的搜索算法。在问题的解空间树中,按照深度优先策略,从根节点出发搜索解空间树。当算法搜索到解空间树的任一节点时,首先判断该节点是否包含问题的解——如果确定不包含,则跳过对以该节点为根的子树的搜索,逐层向其祖先节点回溯;否则,进入该子树,继续按深度优先策略搜索。

求解所有解与单一解的策略差异

在求问题的所有解时,回溯法要回溯到根,且根节点的所有子树都已被搜索过才结束。而在求问题的一个解时,一旦搜索到问题的一个解即可结束搜索。这种以深度优先方式系统搜索问题解的算法称为回溯法,特别适合解决组合数较大的问题。

回溯法的算法框架

回溯法的核心在于“尝试与回溯”。具体到算法实现时,我们通常使用递归或迭代的方式来模拟搜索过程,通过子集树和排列树算法框架来组织数据和搜索空间,实现对问题解空间的系统搜索。

递归回溯与迭代回溯

递归回溯通过函数的自我调用来实现搜索过程的深入与回溯,适用于问题规模较小、递归层次不深的场景。迭代回溯则通过显式栈来模拟递归调用过程,更适用于问题规模较大、需要避免过深递归的情况。

子集树与排列树

子集树算法框架用于解决组合问题,通过“选”或“不选”的方式逐步构建解的子集。排列树算法框架适用于排列问题,通过确定每个位置上的元素来逐步构建解的排列。这两种框架分别对应不同类型的搜索问题,通过深度优先的方式,有效地遍历整个解空间,寻找所有可能的解或特定的解。

 

5.1 回溯法的算法框架

1. 问题的解空间

在深入探索回溯法之前,首先需要理解问题的解空间概念。解空间是指包含问题所有可能解的集合。为了有效应用回溯法,我们必须首先明确定义问题的解空间,确保它至少包含问题的一个(最优)解。这一定义不仅是理论上的要求,也是实际应用中解题的出发点。

解空间的实例:0-1背包问题

以0-1背包问题为例,假设有n种可选择的物品,每种物品可以选择(1)或不选择(0),那么其解空间可以由长度为n的0-1向量组成。这个解空间包括了对所有变量可能的0-1赋值情况。例如,当n=3时,解空间为:

{(0,0,0),(0,1,0),(0,0,1),(1,0,0),(0,1,1),(1,0,1),(1,1,0),(1,1,1)}{(0,0,0),(0,1,0),(0,0,1),(1,0,0),(0,1,1),(1,0,1),(1,1,0),(1,1,1)}

这个集合包含了所有可能的选择组合,即从全不选到全选的所有情况。

解空间的组织

定义问题的解空间后,下一步是将这个解空间组织得既清晰又便于通过回溯法搜索。通常,解空间被组织成树或图的形式,以便于系统地探索所有可能的解。这种组织方式不仅有助于理解问题结构,也是实现算法的关键。

对于上述的0-1背包问题,当n=3时,解空间可以用一棵完全二叉树来表示。在这棵树中,每个节点代表一个决策点——选择(1)还是不选择(0)。树的每一层对应一个物品的选择,从根节点到叶节点的路径代表一种可能的物品组合,即解空间中的一个元素。例如,路径从根节点到某个叶节点(标记为“H”)可能代表选择了所有物品的情况(1,1,1)。

通过这种方式,解空间树不仅清晰地展示了所有可能的解,而且为我们提供了一个高效搜索解空间的框架。每一条从根节点到叶节点的路径都代表了一个完整的解决方案,而回溯法的任务就是遍历这棵树,找到一个或所有满足条件的解。

在后续的部分中,我们将进一步探讨如何通过回溯法在解空间树中进行搜索,包括如何选择路径、如何回溯以及如何利用剪枝等技术来提高搜索效率。

 

 

5.1 回溯法的算法框架(续)

2. 回溯法的基本思想

回溯法是一种通过探索所有可能的候选解来找到所有解的问题解决方案。它的工作原理基于递归地搜索解空间树,并在不满足约束条件或不可能产生更优解的情况下剪枝,从而减少搜索范围。此过程中,深度优先搜索(DFS)是回溯法的核心。

深度优先搜索解空间

确定解空间的组织结构后,回溯法从解空间树的根节点(开始节点)出发,沿树的深度优先进行搜索。这个根节点同时被视为活动节点和当前的扩展节点。搜索过程中,每到达一个新节点,这个新节点就成为新的活动节点和当前的扩展节点。如果在某个扩展节点无法继续向下搜索,则这个节点变成死节点。这时,搜索过程回溯到最近的一个活动节点,并以此节点作为新的扩展节点。这样,回溯法递归地在解空间树中搜索,直到找到所求的解或解空间树中无更多活动节点为止。

示例:0-1背包问题的解空间树搜索

考虑一个具体的0-1背包问题实例,其中物品重量为w=[16,15,15],价值为p=[45,25,25],背包容量为30。从解空间树的根节点开始搜索,初始时,根节点是唯一的活动节点。在扩展节点处,可以选择向下搜索到节点B或节点C。假设首先搜索到节点B,这时,节点A和B都是活动节点,B成为当前的扩展节点。此时,背包的剩余容量为14,获得的价值为45。按此逻辑继续搜索,通过深度优先搜索策略,最终能够找到问题的最优解。

旅行售货员问题的解空间树搜索

旅行售货员问题(TSP)要求找到一条经过所有城市恰好一次且返回出发点的最短或成本最低的路线。这个问题的解空间同样可以组织成树状结构,从树根到任一叶节点的路径代表一种可能的周游路线。通过深度优先搜索,可以探索不同的路线,同时使用剪枝函数避免无效搜索,提高搜索效率。

剪枝优化

在解空间树的搜索过程中,剪枝是优化搜索效率的关键策略。回溯法通常采用两种剪枝策略:约束函数和限界函数。约束函数用于剪去那些不满足问题约束条件的子树,而限界函数则用于剪去那些不能产生比当前已找到的解更优的子树。这两类剪枝策略有效地减少了搜索空间,提高了算法的效率。

通过上述策略,回溯法在解空间树中以深度优先的方式进行搜索,同时通过剪枝函数来避免无效搜索。无论是解决0-1背包问题、旅行售货员问题,还是其他复杂的优化问题,回溯法的这一基本思想都是相同的:通过系统地搜索解空间树并适时剪枝,寻找问题的一个或所有解。

 

 

5.1 回溯法的算法框架(续)

3. 递归回溯

递归回溯是实现回溯法的一种常用方式,它依赖于递归函数来实现解空间树的深度优先搜索。通过递归,每一次函数调用都尝试一个可能的解决方案,直到找到问题的解或探索完所有可能的路径。

递归回溯的工作机制

在递归回溯过程中,算法逐层深入解空间树,每一层代表一个决策阶段。形式参数t表示当前的搜索深度,即当前扩展节点在解空间树中的深度。当t大于某个阈值n时,表明已经到达解空间树的叶节点,此时应记录或输出当前的解。

递归函数的核心是一个循环,遍历当前扩展节点的所有未探索的子树。f(n, t)g(n, t)分别表示在当前扩展节点处,未搜索过的子树的起始编号和终止编号。h(i)则表示在当前扩展节点处,变量x[t]的第i个可选值。Constraint()Bound()分别为约束函数和限界函数,用于判断当前节点是否值得进一步探索。如果Constraint(t)返回true,则表示当前解满足问题的约束条件;如果Bound(t)同样返回true,则表示当前解尚未使目标函数越界,值得继续探索下去。

递归回溯算法的示例代码

void Backtrack(int t) {
    if (t > n) {
        // 当达到叶节点时,输出或记录解
        output(x);
    } else {
        for (int i = f(n, t); i <= g(n, t); i++) {
            x[t] = h(i);
            // 如果当前节点满足约束条件并且未使目标函数越界,则继续探索
            if (Constraint(t) && Bound(t))
                Backtrack(t + 1);
        }
    }
}

在这段代码中,Backtrack函数通过递归调用自身,以深度优先的方式遍历解空间树。每一层的循环尝试所有可能的选项,并通过约束和限界函数来剪枝,从而减少不必要的搜索。当探索到解空间树的叶节点,且该节点满足所有约束时,将记录或输出当前的解。

递归回溯的优势

递归回溯的主要优势在于它的直观性和简洁性。编码简单,逻辑清晰,非常适合解决复杂度不是极高的搜索问题。此外,通过约束和限界函数的合理设计,可以大大提高搜索的效率,减少搜索空间。

然而,需要注意的是,递归回溯也有其局限性,尤其是在解空间极大或搜索深度较深时,可能会遇到栈溢出的问题。因此,对于这类问题,可能需要考虑其他搜索策略,如迭代深化搜索、广度优先搜索或启发式搜索等。

总之,递归回溯是解决搜索问题的一种强大工具,能够通过系统地探索解空间树来寻找问题的解。恰当地应用递归回溯法,可以解决广泛的问题,尤其是那些可以通过逐步决策构建解决方案的问题。

 

 4. 迭代回溯

迭代回溯是另一种实现回溯法的方法,它通过非递归的方式来实现解空间树的深度优先遍历。这种方法避免了递归可能导致的栈溢出问题,特别适合于解空间树深度较大的情况。迭代回溯通过显式地使用栈来跟踪搜索路径,模拟递归调用的行为。

迭代回溯的工作原理

在迭代回溯中,搜索过程是通过一个循环实现的,这个循环试图模拟递归回溯过程中深度优先搜索的行为。搜索从根节点开始,逐步深入,直到找到解或探索完所有可能的路径。与递归回溯相比,迭代回溯需要显式管理搜索状态,包括当前节点的位置以及从根节点到当前节点的路径。

迭代回溯算法的示例代码

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++) {
                x[t] = h(i);
                if (Constraint(t) && Bound(t)) {
                    if (Solution(t))
                        output(x);
                    else
                        t++;
                }
            }
        } else {
            t--;
        }
    }
}

在这个算法中,t表示当前的搜索深度,f(n, t)g(n, t)分别指示当前扩展节点未探索子树的起始和终止编号。h(i)为在当前扩展节点处x[t]的第i个可选值。Constraint(t)Bound(t)分别是约束和限界函数,用于判断当前扩展节点是否满足问题的约束条件,以及是否有继续搜索的必要。

特点和优势

迭代回溯的显著特征是在搜索过程中动态产生问题的解空间,且在任何时刻,算法只保存从根节点到当前扩展节点的路径。这种方式的空间复杂度通常为O(h(n)),其中h(n)是解空间树中从根节点到叶节点的最长路径的长度。这比显式存储整个解空间所需的空间小得多,后者可能需要O(2^n)O(n!)的内存空间。

通过显式地管理栈而不是依赖递归调用的隐式栈,迭代回溯在处理深度搜索问题时提供了更大的灵活性和控制力。它特别适合解决那些解空间深而广、递归深度可能导致栈溢出的问题。然而,迭代回溯的实现通常比递归回溯更为复杂,需要更细致地管理搜索的状态和过程。

总结来说,迭代回溯是一种强大的搜索策略,能够有效地遍历解空间树以找到问题的解。它通过显式的栈操作来避免递归的局限性,使得算法能够应对更复杂或更深层次的搜索问题。

 

5. 子集树与排列树

在回溯法中,解空间树的结构是解决问题的关键。特别地,根据问题的性质,解空间树可以细分为子集树和排列树,这两种树分别对应不同类型的搜索问题。

子集树

子集树用于表示从一个有n个元素的集合中找出满足特定条件的所有子集的问题。例如,0-1背包问题的解空间树就是一种子集树。在这种树中,每个节点代表一个决策点:是否包含集合中的某个元素。因此,一个具有n个元素的集合的子集树通常有2^n个叶节点,其节点总数为2^(n+1) - 1。遍历这样的子集树需要的计算时间是O(2^n),反映了所有可能子集的枚举过程。

搜索子集树的算法框架
void Backtrack(int t) {
    if (t > n)
        output(x); // 输出或记录解
    else {
        for (int i = 0; i <= 1; i++) {
            x[t] = i; // 决定元素t是否包含在子集中
            if (Constraint(t) && Bound(t))
                Backtrack(t + 1); // 满足约束条件,继续探索
        }
    }
}

排列树

排列树用于解决确定n个元素满足某种条件的所有排列的问题。这类问题的解空间树有n!个叶节点,每个叶节点代表一种元素排列。因此,遍历排列树的计算时间是O(n!),显著高于子集树,反映了排列问题的复杂性。

搜索排列树的算法框架
void Backtrack(int t) {
    if (t > n)
        output(x); // 输出或记录解
    else {
        for (int i = t; i <= n; i++) {
            swap(x[t], x[i]); // 将元素i置于位置t
            if (Constraint(t) && Bound(t))
                Backtrack(t + 1); // 满足约束条件,继续探索
            swap(x[t], x[i]); // 恢复原状,以便尝试下一个元素
        }
    }
}

在调用Backtrack(1)开始搜索之前,变量数组x通常初始化为单位排列(1, 2, ..., n),以表示排列的初始状态。

总结

子集树和排列树是解决组合问题的两个基本工具,它们各自对应于不同的问题类型。通过适当的约束条件和剪枝策略,回溯法可以有效地在这些树中搜索解决方案,尽管面临的计算复杂度可能非常高。了解如何构建和遍历这两种类型的树对于使用回溯法解决问题至关重要。

标签:5.1,递归,问题,算法,搜索,回溯,空间,节点
From: https://blog.csdn.net/tang7mj/article/details/137395480

相关文章

  • 回归预测 | Matlab基于CPO-GPR基于冠豪猪算法优化高斯过程回归的多输入单输出回归预测
    回归预测|Matlab基于CPO-GPR基于冠豪猪算法优化高斯过程回归的多输入单输出回归预测目录回归预测|Matlab基于CPO-GPR基于冠豪猪算法优化高斯过程回归的多输入单输出回归预测预测效果基本介绍程序设计参考资料预测效果基本介绍Matlab基于CPO-GPR基于......
  • 机器学习快速入门 第二阶段:高级学习算法(1)
    第二阶段的高级学习算法课程包含58节,我按照相似度,将其分为九个模块,因篇幅较多,分成两个文章来讲,便于大家理解与掌握在本文中我们讲前四部分,目录如下:目录:神经网络的基础神经元和大脑 -这是对人工神经网络的生物学灵感来源的介绍。神经网络中的层 -详细介绍了神经网络中......
  • 基于蜜獾算法优化的核极限学习机(KELM)回归预测
    基于蜜獾算法优化的核极限学习机(KELM)回归预测文章目录基于蜜獾算法优化的核极限学习机(KELM)回归预测1.KELM理论基础2.回归问题数据处理4.基于蜜獾算法优化的KELM5.测试结果6.Matlab代码摘要:本文利用蜜獾算法对核极限学习机(KELM)进行优化,并用于回归预测.1.KEL......
  • FOC算法中为啥用PWM触发ADC中断
    在FOC(FieldOrientedControl,场向量控制)算法中,为什么要使用PWM(PulseWidthModulation,脉宽调制)触发ADC(Analog-to-DigitalConverter,模数转换器)中断呢?在FOC中,PWM被用来控制电机的相电流,以实现精确的控制。通过改变PWM信号的占空比,可以调节电机的转速和转矩。而为了实现精确的控......
  • 【蓝桥杯选拔赛真题56】C++求位数 第十四届蓝桥杯青少年创意编程大赛 算法思维 C++编
    目录C++求位数一、题目要求1、编程实现2、输入输出二、算法分析三、程序编写四、程序说明五、运行结果六、考点分析七、推荐资料C++求位数第十四届蓝桥杯青少年创意编程大赛C++选拔赛真题一、题目要求1、编程实现给定一个正整数N(1<N<10^8),输出N为几位数2、......
  • 《机器学习算法面试宝典》正式发布!
    大家好,历时半年的梳理和修改,《机器学习算法面试宝典》(以下简称《算法面试宝典》)终于可以跟大家见面了。近年来,很多理科专业学生也纷纷转入算法赛道,特别是最近ChatGPT的爆火,推动了AI技术圈对大模型的研究热情,AI就业市场人数越来越多,算法岗已成进入了竞争难度第一梯度(超......
  • C111【模板】莫队算法 P2709 小B的询问
    视频链接:C111【模板】莫队算法P2709小B的询问_哔哩哔哩_bilibili   LuoguP2709小B的询问//普通莫队O(n*sqrt(n))#include<iostream>#include<cstring>#include<algorithm>#include<cmath>usingnamespacestd;constintN=50005;intn,m,k,B,a[N];......
  • Offer必备算法21_回文串dp_六道力扣题详解(由易到难)
    目录①力扣647.回文子串解析代码②力扣5.最长回文子串解析代码③力扣1745.分割回文串IV解析代码④力扣132.分割回文串II解析代码⑤力扣516.最长回文子序列解析代码⑥力扣1312.让字符串成为回文串的最少插入次数解析代码本篇完。①力扣647.回文子串64......
  • SCI一区 | Matlab实现NGO-TCN-BiGRU-Attention北方苍鹰算法优化时间卷积双向门控循环
    SCI一区|Matlab实现NGO-TCN-BiGRU-Attention北方苍鹰算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测目录SCI一区|Matlab实现NGO-TCN-BiGRU-Attention北方苍鹰算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测预测效果基本介......
  • 操作系统综合题之“采用短进程优先调度算法(Shortest-Process-First,SPF)和先来先服务调
    一、问题:某系统中有四个进程,他们进入系统的时间和需要服务的时间如题下表所示(表中数值均为十进制)进程进入系统的时间需要服务的时间P10100P21060P32525P43540 1.采用先来先服务调度算法(FCFS)时,填写题表,并及计算平均周转时间(四舍五入,保留小数后两位......