回溯算法——我欲修仙(功法篇)

news/2025/3/25 13:08:08/

个人主页:【😊个人主页】
系列专栏:【❤️我欲修仙】

壁纸


系列文章目录

第一章 ❤️ 学习前的必知知识
第二章 ❤️ 二分查找


文章目录

  • 系列文章目录
  • 回溯算法🤔🤔🤔
  • 回溯算法一般可以解决的问题
  • 回溯算法的实现
  • 回溯算法的固定模板(回溯三部曲)
    • 回溯函数模板返回值以及参数
    • 回溯函数终止条件
    • 回溯搜索的遍历过程
  • 总结


回溯算法🤔🤔🤔

回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。用回溯算法解决问题的一般步骤为:

1、定义一个解空间,它包含问题的解。
2、利用适于搜索的方法组织解空间。
3、利用深度优先法搜索解空间。
4、利用限界函数避免移动到不可能产生解的子空间。

回溯法也可以叫做回溯搜索法,它是一种搜索的方式。
在二叉树系列中,我们提到过回溯,例如二叉树:
以为使用了递归,其实还隐藏着 回溯 (opens new window)。回溯是递归的副产品,只要有递归就会有回溯。回溯函数也就是递归函数,指的都是一个函数。

问题的解空间通常是在搜索问题的解的过程中动态产生的,这是回溯算法的一个重要特性。

在这里插入图片描述

回溯算法一般可以解决的问题

  • 组合问题:N个数里面按一定规则找出k个数的集合
  • 切割问题:一个字符串按一定规则有几种切割方式
  • 子集问题:一个N个数的集合里有多少符合条件的子集
  • 排列问题:N个数按一定规则全排列,有几种排列方式
  • 棋盘问题:N皇后,解数独等等

回溯算法的实现

使用回溯法解决问题的过程,实际上是建立一棵“状态树”的过程。例如,在解决列举集合{1,2,3}所有子集的问题中,对于每个元素,都有两种状态,取还是舍,所以构建的状态树为:

在这里插入图片描述

回溯算法的求解过程实质上是先序遍历“状态树”的过程。树中每一个叶子结点,都有可能是问题的答案。图中的状态树是满二叉树,得到的叶子结点全部都是问题的解。
在某些情况下,回溯算法解决问题的过程中创建的状态树并不都是满二叉树,因为在试探的过程中,有时会发现此种情况下,再往下进行没有意义,所以会放弃这条死路,回溯到上一步。在树中的体现,就是在树的最后一层不是满的,即不是满二叉树,需要自己判断哪些叶子结点代表的是正确的结果。

回溯算法的固定模板(回溯三部曲)

回溯函数模板返回值以及参数

在回溯算法中,习惯是为函数命名为backtracking,这个起名是随意。
回溯算法中函数返回值一般为void。
回溯算法需要的参数不像二叉树递归的时候那么容易一次性确定下来,所以一般是先写逻辑,然后需要什么参数,就填什么参数。

回溯函数伪代码如下:

void backtracking(参数)

回溯函数终止条件

既然是树形结构,那么我们在讲解二叉树的递归 (opens new window)的时候,就知道遍历树形结构一定要有终止条件。
所以回溯也有要终止条件。
什么时候达到了终止条件,树中就可以看出,一般来说搜到叶子节点了,也就找到了满足条件的一条答案,把这个答案存放起来,并结束本层递归。

所以回溯函数终止条件伪代码如下:

if (终止条件) {存放结果;return;
}

回溯搜索的遍历过程

回溯法一般是在集合中递归搜索,集合的大小构成了树的宽度,递归的深度构成的树的深度。

回溯函数遍历过程伪代码如下:
void backtracking(参数) {if (终止条件) {存放结果;return;}for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {处理节点;backtracking(路径,选择列表); // 递归回溯,撤销处理结果}
}}

for循环就是遍历集合区间,可以理解一个节点有多少个孩子,这个for循环就执行多少次。
函数这里自己调用自己,实现递归。
我们可以从图中看出for循环可以理解是横向遍历,backtracking(递归)就是纵向遍历,这样就把这棵树全遍历完了,一般来说,搜索叶子节点就是找的其中一个结果了。

总结

解决问题时,每进行一步,都是抱着试试看的态度,如果发现当前选择并不是最好的,或者这么走下去肯定达不到目标,立刻做回退操作重新选择。这种走不通就回退再走的方法就是回溯算法。

在这里插入图片描述


http://www.ppmy.cn/news/55780.html

相关文章

Linux命令集(Linux常用命令--echo指令篇)

Linux命令集(Linux常用命令--echo指令篇) Linux常用命令集(echo指令篇)2.echo(echo)1. 输出自定义内容2. 禁止输出末尾换行符3. 转义功能4. 与特殊字符配合使用实现其余功能 Linux常用命令集(echo指令篇) 如…

设计模式:创建型设计模式、结构型设计模式

目录 前言如何学习设计模式?设计模式基础设计原则 一. 创建型设计模式1. 模板方法2. 观察者模式3. 策略模式 二. 结构型设计模式1. 单例模式2. 工厂模式3. 抽象工厂4. 责任链5. 装饰器6. 组合模式 前言 如何学习设计模式? 明确目的 在现有的设计模式上…

Android 系统的分区和文件系统(1)- Android 系统源码结构分析

声明 本文分析Android系统源码各目录存放文件用途。其中参考了一些书籍内容,仅供学习使用。本文采用 LinesgeOS cm-14.1(等同于AOSP Android 7.1.1) 1. 整体结构 各个版本的源码目录基本是类似的,如果是编译后的源码目录&#x…

第十五章 角色移动旋转实例

本章节我们创建一个“RoleDemoProject”工程,然后导入我们之前创建地形章节中的“TerrainDemo.unitypackage”资源包,这个场景很大,大家需要调整场景视角才能看清。 接下来,我们添加一个人物模型,操作方式就是将模型文…

基于台风信息查询 API 设计台风预警系统的基本思路

引言 在过去的几十年中,由于全球气候变化等因素的影响,台风的强度和频率都有所增加,给人类社会带来了极大的威胁。在这种背景下,一个高效可靠的台风预警和监测系统显得尤为重要。这种系统可以通过获取、存储、处理和分析各种相关…

使用aardio写一个基于pyocd的单片机下载器

1 新建工程 最开始本来是打算调用pyocd 的python api的,但是一个是内嵌包一直安装出问题,一个是考虑到本地pack不想重复安装和管理,于是就转做pyocd的前端了,也就是直接调用pyocd,根据返回数据解析,然后执…

ViveNAS - 一个基于LSM tree的文件存储实现 (一)

1. ViveNAS (GitHub - cocalele/ViveNAS) ViveNAS 是一个开源分布式的网络文件系统(NAS), 具有下面的特点: - 通过不同存储介质的结合,在高性能、低成本间寻找动态的平衡 - 解决数据的长期、低成本存储问题&#xff…

使用docker搭建RocketMQ(非集群搭建官方镜像)

之前在使用 RocketMQ 官方的包在搭建的时候,发现好多问题,什么修改内存大小,然后启动 broker 报错,类似 service not available now, maybe disk full 等等… 最后决定还是重新用 docker 搭建下,感觉这样子玩坏了&…