回溯法(Java)

news2024/10/6 22:22:58

回溯法(Java)

文章目录

  • 回溯法(Java)
    • 1、引言
    • 2、回溯法
      • 2.1 定义
      • 2.2 使用场合
      • 2.3 基本做法
      • 2.4 具体做法
      • 2.5 常见例子
    • 3、比较
    • 4、 问题的解空间
      • 4.1 介绍
      • 4.2 解空间(Solution Space)
      • 4.3 举例
    • 5、基本思想
      • 5.1 基本步骤
      • 5.2 常用剪枝函数
      • 5.3 深度优先的问题状态生成法
      • 5.4 宽度优先的问题状态生成法
    • 6、计算复杂性
    • 7、算法框架
    • 8、核心代码
    • 9、参考资料


在这里插入图片描述


1、引言

迷宫问题中的回溯主要体现在当没有路可走时,会退回到上一个岔路口,重新在没有走过的路线中找一个没有走过的路走

  • 理论上

寻找问题的解的一种可靠的方法是首先列出所有候选解,然后依次检查每一个,在检查完所有或部分候选解后,即可找到所需要的解。

  • 事实上

1.当候选解数量有限并且通过检查所有或部分候选解能够得到所需解时,上述方法是可行的。

2.若候选解的数量非常大(指数级,大数阶乘),即便采用最快的计算机也只能解决规模很小的问题。

回溯分支限界法是比较常用的对候选解进行系统检查两种方法。

  • 按照这两种方法对候选解进行系统检查通常会使问题的求解时间大大减少(无论对于最坏情形还是对于一般情形) 。

  • 可以避免对很大的候选解集合进行检查,同时能够保证算法运行结束时可以找到所需要的解。

  • 通常能够用来求解规模很大的问题。

2、回溯法

2.1 定义

回溯法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就「回溯」返回,尝试别的路径。

回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为「回溯点」

深度优先的方式系统地搜索问题的解的算法称为回溯法

2.2 使用场合

  • 对于许多问题,当需要找出它的解的集合或者要求回答什么解是满足某些约束条件的最佳解时,往往要使用回溯法。

  • 这种方法适用于解一些组合数相当大的问题,具有「通用解题法」之称。

2.3 基本做法

基本做法是搜索,或是一种组织得井井有条的,能避免不必要搜索的穷举式搜索法

2.4 具体做法

系统性

回溯法在问题的解空间树中,按深度优先策略,从根结点出发搜索解空间树。

跳跃性

算法搜索至解空间树的任意一点时,先判断该结点是否包含问题的解。如果肯定不包含,则跳过对该结点为根的子树的搜索,逐层向其祖先结点回溯;否则,进入该子树继续按深度优先策略搜索。

2.5 常见例子

图的深度优先遍历

在这里插入图片描述

3、比较

回溯法与穷举查找是一样的吗?

  • 相同点

可以把回溯法和分支限界法看成是穷举法的一个改进。该方法至少可以对某些组合难题的较大实例求解。

  • 不同点

每次只构造侯选解的一个部分。然后评估这个部分构造解:如果加上剩余的分量也不可能求得一个解,就绝对不会生成剩下的分量

4、 问题的解空间

4.1 介绍

  • 问题的解向量

回溯法希望一个问题的解能够表示成一个n元式(x1,x2,…,xn)的形式。

  • 显约束

对分量xi的取值范围的限定。

  • 隐约束

为满足问题的解而对不同分量之间施加的约束。

4.2 解空间(Solution Space)

对于问题的一个实例,解向量满足显式约束条件的所有多元组,构成了该实例的一个解空间。

注意:同一问题可有多种表示,有些表示更简单,所需状态空间更小(存储量少,搜索方法简单)。

4.3 举例

对于有n种可选物品的0-1背包问题

  • 解空间由2n个长度为n的0-1向量组成
  • n=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)}

完全二叉树表示的解空间

  • 边上的数字给出了向量x中第i个分量的值xi
  • 根节点叶节点的路径定义了解问题的一个解

5、基本思想

5.1 基本步骤

  • 针对所给问题,定义问题的解空间

  • 确定易于搜索的解空间结构

  • 深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。

5.2 常用剪枝函数

  • 约束函数扩展结点处剪去不满足约束的子树;

  • 限界函数剪去得不到最优解的子树。

5.3 深度优先的问题状态生成法

  • 如果对一个扩展结点R,一旦产生了它的一个儿子C,就把C当做新的扩展结点

  • 完成对子树C(以C为根的子树)的穷尽搜索之后,将R重新变成扩展结点,继续生成R的下一个儿子(如果存在)。

5.4 宽度优先的问题状态生成法

  • 一个扩展结点变成死结点之前,它一直是扩展结点。

6、计算复杂性

  • 空间复杂性

  • 用回溯法解题的一个显著特征是在搜索过程中「动态产生问题的解空间」。在任何时刻,算法只保存从根结点到当前扩展结点的路径

  • 如果解空间树中从根结点到叶结点的最长路径的长度为h(n),则回溯法所需的计算空间通常为O(h(n))

  • 显式地存储整个解空间则需要O(2h(n)O(h(n)!)内存空间。

7、算法框架

如下图所示:

解空间一般用解空间树(Solution Space Trees,也称状态空间树)的方式组织,树的根结点位于第1层,表示搜索的初始状态,第2层的结点表示对解向量的第一个分量做出选择后到达的状态,第1层到第2层的边上标出对第一个分量选择的结果,依此类推,从树的根结点到叶子结点的路径就构成了解空间的一个可能解。

用完全二叉树表示的解空间(n=3)

左边子树表示1号物品要放入背包 ,右边子树表示1号物品不放入背包
树中的8个叶子结点分别代表该问题的8个可能解。

例如,从跟结点到结点H的路径相应于解空间中元素(1,1,1)

在这里插入图片描述

又如:

在这里插入图片描述

当搜索到一个L结点时,就把这个L结点变成为E结点,继续向下搜索这个结点的儿子结点。当搜索到一个D结点,而还未得到问题的最终解时,就向上回溯到它的父亲结点。如果这个父亲结点当前还是E结点,就继续搜索这个父亲结点的另一个儿子结点;如果这个父亲结点随着所有儿子结点都已搜索完毕而变成D结点,就沿着这个父结点向上,回溯到它的祖父结点。这个过程继续进行,直到找到满足问题的最终解。

8、核心代码

递归回溯

回溯法对解空间作深度优先搜索,因此,在一般情况下用递归方法实现回溯法,t表示搜索深度。

void backtrack (int t){
    if (t >n ) {         //t>n表示算法已搜索到叶节点
        output(x);     //记录或输出得到的可行解x
    } else {
        for (int i = f(n, t); i <= g(n, t); i++) {
            //其中f(n,t),g(n,t)分别表示在当前扩展结点处未搜索过的子树的起始编号和终止编号。
            x[t] = h(i);    //h(i)表示在当前扩展节点处x[t]的第i个可选值
            if (constraint(t) && bound(t))
                backtrack(t + 1);
        }
    }
}

if (Constraint(t)&&Bound(t) ) backtrack(t + 1);

if语句含义:Constraint(t)和Bound(t)表示当前扩展节点处的约束函数和限界函数。

  • Constraint(t): 返回值为true时,在当前扩展节点处x[1:t]的取值满足问题的约束条件,否则不满足问题的约束条件,可剪去相应的子树

  • Bound(t): 返回的值为true时,在当前扩展节点处x[1:t]的取值为目标函数不越界,还需由backtrack(t+1)对其相应的子树做进一步搜索。否则,当前扩展节点处x[1:t]的取值是目标函数越界,可剪去相应的子树

  • 递归出口:backtrack(t)执行完毕,返回t-1层继续执行,对还没有测试过的x[t-1]的值继续搜索。当t=1时,若以测试完x[1]的所有可选值,外层调用就全部结束。

迭代回溯

采用树的非递归深度优先遍历算法,可将回溯法表示为一个非递归迭代过程。

void iterativeBacktrack(){
    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--;    //回溯到上一节点
        }
    }
}

分析:

  • Constraint(t):约束函数,剪枝条件(剪去不可行解)
  • Bound(t):限界函数,剪枝条件(剪去不可能最优的解)
  • Solution(t):判断在当前扩展节点处是否已得到问题的可行解。它返回值为true时,当前扩展节点处x[1:t]是问题的可行解。此时,由Output(x)记录或输出得到的可行解。它的返回值为false时,在当前扩展结点处x[1:t]只是问题的部分解,还需向纵深方向继续搜索。
  • 搜索边界: f(n,t)和g(n,t)

9、参考资料

  • 算法设计与分析(第四版)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/45838.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Starday跨境电商平台靠“三快”取胜

入驻快、支付快、物流快 在这个瞬息万变的互联网世界&#xff0c;追求“快”已经成为各行各业的共识&#xff0c;而对于一个因互联网发展而诞生的新兴行业——跨境电商行业&#xff0c;“快”就是跨境电商行业的第一生产力&#xff0c;要想在众多的跨境电商行业中成功出圈&…

【allegro 17.4软件操作保姆级教程六】布线操作基础之一

目录 1.1走线和修线 1.2 Copy操作 1.3 change操作 1.4 删除操作 1.5 Z-copy操作 1.6 Sub-drawing操作 1.1走线和修线 这两个操作是布线时用的最多最基础的操作。如下图&#xff0c;左边是走线命令&#xff08;add connect&#xff09;&#xff0c;右边是修线命令&#x…

外卖项目(项目优化3)12---前后端分离开发

目录 问题描述&#xff1a;184 一、前后端分离开发 185 1.1介绍 185 1.2开发流程 1.3前端技术栈 二、YAPI 186 2.1介绍 2.2使用方式 三、Swagger 187 3.1介绍 3.2使用方式&#xff08;步骤&#xff09; 3.3Swagger---常用注解 188 四、项目部署 189 4.1部署架构…

虹科分享 | 网络流量监控 | 使用 ntopng 收件人和端点进行灵活的警报处理

在之前&#xff0c;ntopng引擎对所有警报的配置是单一的&#xff1a;进入偏好页面并指定警报的发送地点。但这是不理想的&#xff0c;原因有很多&#xff1a;包括不可能在不同的渠道向不同的收件人发送警报&#xff0c;或有选择地决定何时发送警报。 出于这个原因&#xff0c;…

【教材】20022/11/28[指针] 指针数组

一个数组,若其元素均为指针类型数据,称为指针数组,也就是说,指针数组中的每一个元素都存放一个地址,相当于一个指针变量。下面定义一个指针数组:int *p[4] 注意不要写成int &#xff08;*p&#xff09;[4]. 可以分别定义一些字符串,然后用指针数组中的元素分别指向各字符串,在n…

二手闲置物品交易数据快照

近年来&#xff0c;中国社会消费品零售总额不断增长&#xff0c;2019 年1-4 月,消费品零售总额达到128375.8 亿元&#xff0c;同比增长8%。消费者购买力的增强和电商行业的发展&#xff0c;给购买行为提供便利条件&#xff0c;消费者冲动消费后的闲置产品&#xff0c;给二手交易…

《前端》JavaScript总结

文章目录js的使用方法变量与运算符let 与 const变量类型运算符输入与输出输入输出格式化字符串判断语句循环语句for循环while循环do...while循环对象数组访问数组中的元素数组常用属性和函数函数类定义继承静态方法静态变量事件鼠标键盘表单窗口js的使用方法 **使用方式&#…

网络安全工程师必备证书有哪些?

网络环境之间的竞争&#xff0c;归根到底优秀人才之间的竞争。 在2022年网络安全周上&#xff0c;《网络安全人才实战能力白皮书》正式公布。资料显示&#xff0c;到2027年&#xff0c;我国网络安全人员缺口将达327万&#xff0c;而高校人才培养经营规模仅是3万/年。 那样&am…

上半年亏损之下,卫龙第三次冲刺港股IPO

据港交所文件显示&#xff0c;今年6月27日卫龙美味通过港交所上市聆听&#xff0c;11月24日&#xff0c;卫龙更新了聆听后资料集。若此次上市成功&#xff0c;卫龙将成为港股乃至国内辣条第一股。 此前&#xff0c;卫龙已经两度申请了赴港IPO&#xff0c;但都功败垂成&#xff…

看看咱是如何用MATLAB白嫖遥遥领先于同行的神仙级翻译工具 — DeepL

伙伴们不用惊讶&#xff0c;标题仅仅是借用余大嘴的专用修饰语“遥遥领先于同行”而已&#xff0c;但讲DeepL翻译器遥遥领先于同行也不为过&#xff0c;下图是官方给出的采用盲测的方式与其他同类产品的对比图&#xff0c;这应该不是吹牛X&#xff1a; 如此优秀的翻译神器&…

免改造密码方案入选工信部“首届全国商用密码应用优秀案例”

2022年8月18日&#xff0c;“首届全国商用密码应用优秀案例”评选结果重磅揭晓&#xff0c;炼石网络与陕西移动联合打造的“面向重要数据与个人信息保护的商用密码解决方案”&#xff0c;凭借创新性及技术优势&#xff0c;从102个案例中脱颖而出、成功入选&#xff0c;并被收录…

yolov4训练数据: cuda和cudnn的安装

近期再搞openvinoYolov4目标检测&#xff0c;记录一下cuda和cudnn的安装笔记。 mirrors / alexeyab / darknet GitCode 1.cuda的安装 cuDNN Archive | NVIDIA Developer wget https://developer.download.nvidia.com/compute/cuda/10.2/Prod/local_installers/cuda_10.2.89_…

【SVM时序预测】基于matlab鲸鱼算法优化支持向量机SVM时序数据预测【含Matlab源码 2250期】

⛄一、鲸鱼算法优化支持向量机SVM 1 鲸鱼优化算法 WOA是由Mirjalili和Lewis在2016年提出的一种较为新颖的元启发式群体智能优化算法&#xff0c;该算法模仿座头鲸的“螺旋气泡网”捕食策略&#xff0c;如图1所示。 图1 座头鲸“螺旋起泡网”捕食策略 WOA算法寻优步骤如下。 步…

详解企业财务数字化转型路径|推荐收藏

许多企业在推动各大业务部门进行数字化转型时&#xff0c;往往会忽略财务部门。然而&#xff0c;作为掌握公司核心资源与数据和推动企业信息化建设的部门&#xff0c;财务部门也应成为企业数字化转型的重要突破口。 财务数字化转型是运用信息技术等手段对财务数据进行统计、记录…

【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)

需要源码请点赞关注收藏后评论区留言私信~~~ 一、OpenGL ES简介 虽然OpenGL的三维制图功能非常强大&#xff0c;但是它主要为计算机设计的&#xff0c;对于嵌入式设备和移动端设备来说显得比较臃肿&#xff0c;所以业界又设计了专供嵌入式设备的OpenGL ES 它相当于OpenGL的精简…

GPS定位原理

GPS卫星&#xff1a; 卫星定位系统是一种使用卫星对某物进行准确定位的技术&#xff0c;它从最初的定位精度低、不能实时定位、难以提供及时的导航服务&#xff0c;发展到现如今的高精度GPS全球定位系统&#xff0c;实现了在任意时刻、地球上任意一点都可以同时观测到4颗卫星&a…

OS_虚拟内存@请求分页系统@驻留集@内存分配策略

文章目录OS_虚拟内存请求分页系统驻留集内存分配策略请求分页系统页表机制缺页中断机构地址变换机构页框分配驻留集分配策略固定分配可变分配置换策略局部置换全局置换策略组合固定分配局部置换可变分配全局置换可变分配局部置换&#x1f388;OS_虚拟内存请求分页系统驻留集内存…

docker中安装并启动rabbitMQ

docker中安装并启动rabbitMQ1、安装rabbitMQ1.1、拉取镜像1.2、启动容器实例1.3、开启web界面管理插件1.4、浏览器访问 rabbitMQ2、解决Docker部署rabbitmq遇到的如下两个问题&#xff1a;2.1、访问交换机时报错&#xff0c;Management API returned status code 5002.2、访问c…

003. 电话号码的字母组合——回溯算法

1.题目链接&#xff1a; 17. 电话号码的字母组合 2.解题思路&#xff1a; 2.1.题目要求&#xff1a; 给定一个仅包含数字 2-9 的字符串 digits &#xff0c;返回所有它能表示的字母组合。 数字和字母的关系&#xff1a; 例子&#xff1a; 输入&#xff1a;"23" …

测试用例中遇到的常见问题

1、测试用例是什么? 测试用例的设计就是如何覆盖所有软件表现出来的状态&#xff0c;即在满足输入/输出的一组条件下&#xff0c;软件运行时一系列有次序的、受控制的状态变化过程 2、设计用例是否有必要? 将测试内容记录下来&#xff0c;避免了在执行的时候部分测试点被遗…