回溯法

简介: 回溯法就是一种有组织的系统化搜索技术,可以看作是蛮力法穷举搜索的改进。

回溯法就是一种有组织的系统化搜索技术,可以看作是蛮力法穷举搜索的改进。

回溯法每次只构造可能解的一部分,然后评估这个部分解,如果这个部分解有可能导致一个完整解,则对其进一步构造,否则,就不必继续构造这个部分解了。回溯法常常可以避免搜索所有的可能解,所以,它适用于求解组合数量较大的问题。

概述

问题的解空间

复杂问题常常有很多的可能解,这些可能解构成了问题的解空间。解空间也就是进行穷举的搜索空间,所以,解空间中应该包括所有的可能解。

为了用回溯法求解一个具有n个输入的问题,一般情况下,将其可能解表示为满足某个约束条件的等长向量X=(x1,x2,……,xn),其中分量xi(1<=i<=n)的取值范围是某个有限几何Si={ai1,ai2,……,airi},所有可能的解向量构成了问题的解空间。

问题的解空间一般用解空间树的方式组织,因为解空间树能将解空间形象化。如0/1背包问题,

解空间的动态搜索

蛮力法是对整个解空间树中的所有可能解进行穷举搜索的一种方法,但是,只有满足约束条件的解才是可行解,只有满足目标函数的解才是最优解,这就有可能减少搜索空间。回溯法从根节点出发,按照深度优先策略遍历解空间树,搜索满足约束条件的解。在搜索至树中任一结点时,先判断该结点对应的部分解是否满足约束条件,或者是否超出目标函数的界,也就是判断该节点是否包含问题的(最优)解,如果肯定不包含,则跳过对以该结点为根的子树的搜索,即所谓的剪枝;否则,进入以该结点为根的子树,继续按照深度优先策略搜索。

回溯法的搜索过程涉及的结点只是整个解空间树的一部分,在搜索过程中,通常采用两种策略避免无效搜索:(1)用约束条件减去得不到可行解的子树;(2)用目标函数剪去得不到最优解的子树。这两类函数统称为剪枝函数。

回溯法的求解过程

图问题中的回溯法

图着色问题

图着色问题描述为:给定无向连通图G=(V,E)和正整数m,求最小的整数m,使得用m种颜色对G中的顶点着色,使得任意两个相邻顶点着色不同。

首先把所有顶点的颜色初始化为0,然后依次为每个顶点着色。在图着色问题的解空间树中,如果从根节点到当前节点对应一个部分解,也就是所有的颜色指派都没有冲突,则在当前节点处选择第一棵子树继续搜索,也就是为下一个顶点着颜色1,否则,对当前子树的兄弟子树继续搜索,也就是为当前顶点着色下一个颜色,如果所有m种颜色都已尝试过并且发生冲突,则回溯到当前节点的父结点处,上一个顶点的颜色被改变,以此类推。

对于下图中求解三着色问题,在解空间树中,从根节点出发,搜索第一棵子树,即为顶点A着颜色1,再搜索节点2的第一棵子树,即为顶点B着颜色1,这导致一个不可行解,回溯到节点2,选择节点2的第二棵子树,即为顶点B着颜色2,在为顶点C着色时,经过着颜色1和2的失败尝试后,选择节点4的第三棵子树,即为顶点C着颜色3,在节点7选择第一颗子树,就为顶点D着颜色1,但是在为顶点E着色时,顶点E无论着3种颜色的哪一种均发生冲突,于是导致回溯,在节点7选择第二棵子树也会发生冲突,于是,选择节点7的第三棵子树,即顶点D着颜色3,在节点10选择第一棵子树,即为顶点E着颜色1,得到了一个解(1,2,3,3,1)。注意到,解空间树中共有243个节点,而回溯法只搜索了其中的14个节点后就找到了问题的解。

  1. 416. 分割等和子集 - 中等 代码

哈密顿回路问题

要求从一个城市出发,经过每个城市恰好一次,然后回到出发城市。

下图(a)所示是一个无向图,在解空间树中从根结点1开始搜索。首先将x1值为1,到达结点2,表示哈密顿回路从顶点1开始。然后将x2置为1,到达结点3,但顶点1重复访问,搜索节点3的兄弟子树,将x2置为2,构成哈密顿回路的部分解(1,2),在经过节点5和节点6的失败尝试后,将x3置为3,将哈密顿回路的部分解扩展到(1,2,3),在经过节点8、节点9和节点10的失败尝试后,将x4置为4,将哈密顿回路的部分解扩展到(1,2,3,4),在经过节点12、节点13、节点14和节点15的失败的尝试后,将x5置为5,将哈密顿回路的部分解扩展到(1,2,3,4,5),但是在图(a)中从顶点5到顶点1没有边,引起回溯;将x4置为5,到达节点17,构成哈密顿回路的部分解(1,2,3,5),在经过节点18、19和20的失败的尝试后,将x5置为4,将哈密顿回路的部分解扩展到(1,2,3,5,4),而在图(a)中从顶点4到顶点1存在边,所以,找到了一条哈密顿回路(1,2,3,5,4,1),搜索过程结束。注意到,解空间树中共有243个节点,而回溯法只搜索了其中的21个节点后就找到了问题的解。在解空间树中的搜索构成如图(b)所示。

  1. 257. 二叉树的所有路径 - 简单 代码

组合问题中的回溯法

八皇后问题

八皇后问题是19世纪著名的数学家高斯与1850年提出来的。问题是:在8*8的棋盘上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上。

以使用回溯法计算四皇后问题举例。

回溯法从空棋盘开始,首先把皇后1摆放到它所在行的第一个可能的位置,也就是第一行第一列;对于皇后2,在经过第一列和第二列的失败的尝试后,把它摆放到第一个可能的位置,也就是第二行第三列;对于皇后3,把它摆放到第三行的哪一列上都会引起冲突,所以,进行回溯,回到对皇后2的处理,把皇后2摆放到下一个可能的位置,也就是第二行第四列;然后,皇后3摆放到第三行的哪一列上都会引起冲突,再次进行回溯,回到对皇后2的处理,但此时皇后2位于棋盘的最后一列,继续回溯,回到对皇后1的处理,把皇后1摆放到下一个可能的位置,也就是第一行第二列,接下来,把皇后2摆放到第二行第四列的位置,把皇后3摆放到第三行第一列的位置,把皇后4摆放到第四行第三列的位置,这就是四皇后问题的一个解,在解空间树中的搜索过程如图所示。在n=4的情况下,解空间树共有65个节点,24个叶子节点,但实际搜索过程中,遍历操作只涉及8个节点,在24个叶子节点中,仅遍历一个叶子节点就找到了满足条件的解。

  1. 面试题 08.12. 八皇后 - 困难 代码
  2. 51. N 皇后 - 相同题目
  3. 52. N皇后 II - 相同题目

批处理作业调度问题

n个作业{1,2,……,n}要在两台机器上处理,每个作业必须先由机器1处理,然后再由机器2处理,机器1处理作业i所需时间为ai,机器2处理作业i所需时间为bi(1<=i<=n),批处理作业调度问题要求确定这n个作业的最优处理顺序,使得从第1个作业在机器1上处理开始,到最后一个作业在机器2上处理结束所需时间最少。

显然批处理作业的一个最优调度应使机器1没有空闲时间,且机器2的空闲时间最小。可以证明,存在一个最优作业调度,使得在机器1和机器2上作业以相同次序完成。

例如,有3个作业{1,2,3},这3个作业在机器1上所需的处理时间为(2,3,2),在机器2上所需的处理时间为(1,1,3),则这3个作业存在6种可能的调度方案:(1,2,3)、(1,3,2)、(2,1,3)、(2,3,1)、(3,1,2)、(3,2,1),相应的完成时间为10,8,10,9,8,8,如下图所示。显然,最佳调度方案是(1,3,2)、(3,1,2),其完成时间为8。

  1. 332. 重新安排行程 - 中等 代码

总结

回溯法解题一般有两种方式,递归和迭代。比较推荐递归的方式,相对于迭代,思路上更加容易理解。

回溯法其实就是深度优先遍历,整体比较简单,能够用来计算很多的问题,在计算过程中,如果有更多的剪枝条件,可能进一步加快计算出结果的速度。

本章讲述的几道题建议都写一下,每道题都不太一样,练完之后,中等难度的回溯法题目就没有太大问题。

最后

大家如果喜欢我的文章,可以关注我的公众号(程序员麻辣烫)

我的个人博客为:https://shidawuhen.github.io/

往期文章回顾:

算法

  1. 算法学习计划
  2. 蛮力法
  3. 分治法
  4. 减治法
  5. 动态规划法
  6. 贪心法
  7. 回溯法

技术

  1. 微服务之服务框架和注册中心
  2. Beego框架使用
  3. 浅谈微服务
  4. TCP性能优化
  5. 限流实现1
  6. Redis实现分布式锁
  7. Golang源码BUG追查
  8. 事务原子性、一致性、持久性的实现原理
  9. CDN请求过程详解
  10. 记博客服务被压垮的历程
  11. 常用缓存技巧
  12. 如何高效对接第三方支付
  13. Gin框架简洁版
  14. InnoDB锁与事务简析

读书笔记

  1. 敏捷革命
  2. 如何锻炼自己的记忆力
  3. 简单的逻辑学-读后感
  4. 热风-读后感
  5. 论语-读后感
  6. 孙子兵法-读后感

思考

  1. 对项目管理的一些看法
  2. 对产品经理的一些思考
  3. 关于程序员职业发展的思考
  4. 关于代码review的思考
  5. Markdown编辑器推荐-typora
相关文章
|
安全 Linux 网络安全
/var/log/secure日志详解
Linux系统的 `/var/log/secure` 文件记录安全相关消息,包括身份验证和授权尝试。它涵盖用户登录(成功或失败)、`sudo` 使用、账户锁定解锁及其他安全事件和PAM错误。例如,SSH登录成功会显示&quot;Accepted password&quot;,失败则显示&quot;Failed password&quot;。查看此文件可使用 `tail -f /var/log/secure`,但通常只有root用户有权访问。
3801 4
|
Ubuntu
Ubuntu系统镜像下载,国内镜像站大全(山大/清华/阿里/浙大/中科大...)
装Ubuntu,是很多理工科同学入门的第一个挑战,首先我们就需要找到一个能用的iso镜像,根据你的网络环境的不同,不同的站点下载速度会不一样,下面列举一下几个比较好用的,都是来自Ubuntu官方推荐镜像站链接导航国内分区
11103 1
|
1月前
|
机器学习/深度学习 人工智能 自然语言处理
GPT与BERT深度解析:Transformer的双子星架构
GPT基于Transformer解码器,擅长文本生成;BERT基于编码器,专注文本理解。二者在架构、注意力机制和训练目标上差异显著,分别适用于生成与理解任务,体现了AI智能的多元化发展。
|
8月前
|
存储 人工智能 JSON
传统OCR集体阵亡!Versatile-OCR-Program:开源多语言OCR工具,精准解析表格和数学公式等复杂结构
本文解析开源OCR工具Versatile-OCR-Program的技术实现,其基于多模态融合架构实现90%以上识别准确率,支持数学公式与图表的结构化输出,为教育资料数字化提供高效解决方案。
1086 5
传统OCR集体阵亡!Versatile-OCR-Program:开源多语言OCR工具,精准解析表格和数学公式等复杂结构
|
机器学习/深度学习 人工智能 物联网
快速玩转 Llama2 机器学习 PAI 最佳实践(一)低代码 Lora 微调及部署
采用阿里云机器学习平台PAI-快速开始模块针对 Llama-2-7b-chat 进行开发。PAI-快速开始支持基于开源模型的低代码训练、布署和推理全流程,适合想要快速开箱体验预训练模型的开发者。
69554 59
|
9月前
|
人工智能 BI API
Dify-Plus:企业级AI管理核弹!开源方案吊打SaaS,额度+密钥+鉴权系统全面集成
Dify-Plus 是基于 Dify 二次开发的企业级增强版项目,新增用户额度、密钥管理、Web 登录鉴权等功能,优化权限管理,适合企业场景使用。
1403 3
Dify-Plus:企业级AI管理核弹!开源方案吊打SaaS,额度+密钥+鉴权系统全面集成
|
7月前
|
前端开发 网络协议 应用服务中间件
Netty基础—7.Netty实现消息推送服务
本文详细介绍了如何使用Netty实现HTTP服务器、WebSocket以及基于WebSocket的消息推送系统。首先,通过解析HTTP请求和响应消息,展示了Netty在性能和可靠性上的优势,并提供了具体代码示例。接着,分析了HTTP协议的弊端及Ajax短轮询的不足,引出WebSocket全双工通信的优势,包括连接建立、数据处理逻辑与ping-pong探测等。最后,构建了一个完整的消息推送系统,涵盖PushServer、运营客户端与浏览器客户端的交互过程,实现了全连接推送和实时消息传递。
|
人工智能 自然语言处理 机器人
对话阿里云 CIO 蒋林泉:AI 时代,企业如何做好智能化系统建设?
10 月 18 日, InfoQ《C 位面对面》栏目邀请到阿里云 CIO 及 aliyun.com 负责人蒋林泉(花名:雁杨),就 AI 时代企业 CIO 的角色转变、企业智能化转型路径、AI 落地实践与人才培养等主题展开了讨论。
24162 69
对话阿里云 CIO 蒋林泉:AI 时代,企业如何做好智能化系统建设?
|
SQL XML JavaScript
【若依Java】15分钟玩转若依二次开发,新手小白半小时实现前后端分离项目,springboot+vue3+Element Plus+vite实现Java项目和管理后台网站功能
摘要: 本文档详细介绍了如何使用若依框架快速搭建一个基于SpringBoot和Vue3的前后端分离的Java管理后台。教程涵盖了技术点、准备工作、启动项目、自动生成代码、数据库配置、菜单管理、代码下载和导入、自定义主题样式、代码生成、启动Vue3项目、修改代码、以及对代码进行自定义和扩展,例如单表和主子表的代码生成、树形表的实现、商品列表和分类列表的改造等。整个过程详细地指导了如何从下载项目到配置数据库,再到生成Java和Vue3代码,最后实现前后端的运行和功能定制。此外,还提供了关于软件安装、环境变量配置和代码自动生成的注意事项。
28956 73
|
存储 网络架构
Next.js 实战 (四):i18n 国际化的最优方案实践
这篇文章介绍了Next.js国际化方案,作者对比了网上常见的方案并提出了自己的需求:不破坏应用程序的目录结构和路由。文章推荐使用next-intl库来实现国际化,并提供了详细的安装步骤和代码示例。作者实现了国际化切换时不改变路由,并把当前语言的key存储到浏览器cookie中,使得刷新浏览器后语言不会失效。最后,文章总结了这种国际化方案的优势,并提供Github仓库链接供读者参考。
756 0
Next.js 实战 (四):i18n 国际化的最优方案实践