回溯算法中关于剪枝的一些应用

embedded/2025/2/8 1:26:07/

在这里插入图片描述
衔接上篇( ^ _ ^ )
剪枝优化是回溯算法中一种重要的优化手段,其核心思想是 提前终止无效的递归分支,避免无意义的搜索,从而大幅减少计算量。通过合理剪枝,可以将指数级的时间复杂度降低到更优的水平。


一、剪枝的核心思想

在递归遍历决策树时,提前判断当前路径是否可能得到有效解

  • 不可能得到解 → 直接终止当前分支的递归(“剪掉”这个分支)
  • 可能得到解 → 继续递归探索

二、剪枝的常见类型及示例

1. 可行性剪枝

在每一步判断当前路径是否满足问题的约束条件,若不满足则提前返回。
示例:组合总和问题

void backtrack(vector<int>& nums, int remain, int start, vector<int>& path, vector<vector<int>>& res) {if (remain < 0) return;  // ✂️剪枝:剩余值为负数时直接返回if (remain == 0) {res.push_back(path);return;}for (int i = start; i < nums.size(); ++i) {if (nums[i] > remain) break;  // ✂️剪枝:已排序,后续元素更大,无需尝试path.push_back(nums[i]);backtrack(nums, remain - nums[i], i, path, res);path.pop_back();}
}

关键点

  • 先对数组排序(sort),使后续元素递增
  • nums[i] > remain 时,后续元素必然更大,不可能满足条件 → 直接break

2. 重复性剪枝

避免生成重复的解(常见于元素有重复值的问题)。
示例:全排列II(含重复元素)

void backtrack(vector<int>& nums, vector<bool>& used, vector<int>& path, vector<vector<int>>& res) {if (path.size() == nums.size()) {res.push_back(path);return;}for (int i = 0; i < nums.size(); ++i) {// ✂️剪枝条件1:跳过已使用的元素if (used[i]) continue;  // ✂️剪枝条件2:跳过重复元素(需先排序)if (i > 0 && nums[i] == nums[i-1] && !used[i-1]) continue;used[i] = true;path.push_back(nums[i]);backtrack(nums, used, path, res);path.pop_back();used[i] = false;}
}

关键点

  • 先对数组排序(sort),使相同元素相邻
  • nums[i] == nums[i-1]!used[i-1] 时,说明前一个相同元素未被使用 → 当前分支会产生重复解 → 跳过

3. 对称性剪枝

利用问题本身的对称性,避免重复搜索对称解。
示例:生成回文数
在生成回文数时,只需构造前半部分,后半部分对称生成即可。


三、剪枝的实现技巧

技巧适用场景示例
排序 + 提前终止循环组合问题、子集问题if (nums[i] > remain) break
索引标记(start避免重复选择元素组合问题中的 for (i = start)
哈希表记录已访问状态棋盘类问题(如数独)记录某行/列/宫是否包含某数字
数学性质推导利用数学公式提前排除不可能的情况N皇后问题的斜线检查

四、剪枝的意义

  1. 时间复杂度优化:将指数级复杂度降低到更优水平(例如从 O(n!) 优化到 O(n×n!))
  2. 空间优化:减少递归深度和内存占用
  3. 实际效率提升:对于大规模输入,剪枝可能将不可行的问题变为可解

五、经典剪枝练习

  1. 组合总和II(不可重复选相同元素):if (i > start && nums[i] == nums[i-1]) continue
  2. 子集II(含重复元素):if (i > start && nums[i] == nums[i-1]) continue
  3. 数独求解:预先记录每行/列/宫已使用的数字,快速判断是否可填

六、总结

剪枝是回溯算法的灵魂,核心在于通过问题特性提前终止无效递归
关键步骤

  1. 明确问题的约束条件
  2. 分析决策树中哪些分支必然无效
  3. 设计剪枝条件,用代码实现提前终止
  4. 通过排序、哈希表等工具辅助剪枝判断

http://www.ppmy.cn/embedded/160423.html

相关文章

【数据结构篇】时间复杂度

一.数据结构前言 1.1 数据结构的概念 数据结构(Data Structure)是计算机存储、组织数据的⽅式&#xff0c;指相互之间存在⼀种或多种特定关系的数 据元素的集合。没有⼀种单⼀的数据结构对所有⽤途都有⽤&#xff0c;所以我们要学各式各样的数据结构&#xff0c; 如&#xff1a…

洛谷P2638 安全系统

安全系统 题目描述 特斯拉公司的六位密码被轻松破解后&#xff0c;引发了人们对电动车的安全性能的怀疑。李华听闻后&#xff0c;自己设计了一套密码&#xff1a; 假设安全系统中有 n n n 个储存区&#xff0c;每个储存区最多能存储存 2 2 2 种种类不同的信号&#xff08;…

【Uniapp-Vue3】从uniCloud中获取数据

需要先获取数据库对象&#xff1a; let db uniCloud.database(); 获取数据库中数据的方法&#xff1a; db.collection("数据表名称").get(); 所以就可以得到下面的这个模板&#xff1a; let 函数名 async () > { let res await db.collection("数据表名称…

Flowmix/Docx 多模态文档编辑器春节更新!日期组件 + 一键生成区块链接,效率飞升!...

hi, 大家好, 我是徐小夕. 最近 flowmix/docx 多模态文档编辑器在春节期间又做了一波新功能的迭代&#xff0c;致力于帮助企业构建专业级文档知识编辑器. 接下来和大家分享一下我们最近的更新&#xff1a; 体验地址: https://flowmix.turntip.cn 在和大家分享更新功能之前&…

【2025年更新】1000个大数据/人工智能毕设选题推荐

文章目录 前言大数据/人工智能毕设选题&#xff1a;后记 前言 正值毕业季我看到很多同学都在为自己的毕业设计发愁 Maynor在网上搜集了1000个大数据的毕设选题&#xff0c;希望对大家有帮助&#xff5e; 适合大数据毕业设计的项目&#xff0c;完全可以作为本科生当前较新的毕…

【hot100】刷题记录(8)-矩阵置零

题目描述&#xff1a; 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]]示例 2…

记录 | WPF创建和基本的页面布局

目录 前言一、创建新项目注意注意点1注意点2 解决方案名称和项目名称 二、布局2.1 Grid2.1.1 RowDefinitions 行分割2.1.2 Row & Column 行列定位区分 2.1.3 ColumnDefinitions 列分割 2.2 StackPanel2.2.1 Orientation 修改方向 三、模板水平布局【Grid中套StackPanel】中…

优化fm.jiecao.jcvideoplayer_lib中视频横竖屏自动适配原视频方案

fm.jiecao:jiecaovideoplayer:x.x.x 优化fm.jiecao.jcvideoplayer_lib中视频横竖屏自动适配原视频方案&#xff1a; 仅优化关键代码部分&#xff0c;源码&#xff1a; public void startWindowFullscreen() {Log.i(TAG, "startWindowFullscreen " " [" …