【基础算法】初识搜索:递归型枚举与回溯剪枝

文章目录

  • 一、搜索
    • 1. 什么是搜索?
    • 2. 遍历 vs 搜索
    • 3. 回溯与剪枝
  • 二、OJ 练习
    • 1. 枚举子集 ⭐
      • (1) 解题思路
      • (2) 代码实现
    • 2. 组合型枚举 ⭐
      • (1) 解题思路
    • 请添加图片描述
      • (2) 代码实现
    • 3. 枚举排列 ⭐
      • (1) 解题思路
      • (2) 代码实现
    • 4. 全排列问题 ⭐
      • (1) 解题思路
      • (2) 代码实现

一、搜索

1. 什么是搜索?

搜索,是一种枚举,通过穷举所有的情况来找到最优解,或者统计合法解的个数。因此,搜索有时候也叫作暴搜。 搜索一般分为深度优先搜索 (DFS) 与宽度优先搜索 (BFS) 。

2. 遍历 vs 搜索

深度优先遍历 vs 深度优先搜索,宽度优先遍历 vs 宽度优先搜索?遍历是形式,搜索是目的。 不过,在一般情况下,我们不会去纠结概念的差异,两者可以等同。

3. 回溯与剪枝

回溯:当在搜索的过程中,遇到走不通或者走到底的情况时,就回头。

剪枝:剪掉在搜索过程中,重复出现或者不是最优解的分支。


二、OJ 练习

1. 枚举子集 ⭐

【题目链接】

B3622 枚举子集(递归实现指数型枚举) - 洛谷

【题目描述】

今有 nnn 位同学,可以从中选出任意名同学参加合唱。

请输出所有可能的选择方案。

【输入格式】

仅一行,一个正整数 nnn

【输出格式】

若干行,每行表示一个选择方案。

每一种选择方案用一个字符串表示,其中第 iii 位为 Y 则表示第 iii 名同学参加合唱;为 N 则表示不参加。

需要以字典序输出答案。

【示例一】

输入

3

输出

NNN
NNY
NYN
NYY
YNN
YNY
YYN
YYY

【说明/提示】

对于 100%100\%100% 的数据,保证 1≤n≤101\leq n\leq 101n10


(1) 解题思路

对于题目中给的示例来说,我们一共有 3 个人,也就是说我们有三个字母需要填,那么对于每一个字母都有两种情况,我们不妨画出一个树状图来展示枚举的过程。

请添加图片描述

这样的一棵树状图又可以被称为决策树,它能够很好的帮助我们枚举出最后的答案,我们想要获取答案实质上就是对这一棵树进行一次深度优先遍历 (DFS) 。

接下来我们只需要模拟一遍这个决策树的过程即可。怎么模拟?首先,我们肯定是需要用到递归函数的,那么递归函数内部该如何设计?这就要看我们的决策树了。函数体的主体部分就是在模拟决策树的每一层都干了些什么,结束条件就是到叶子节点的时候。


(2) 代码实现

#include<iostream>using namespace std;string path;  // 记录递归过程中,每一步的决策
int n;void dfs()
{if(path.size() == n)  // 如果大小为n了说明到叶子节点了,需要输出{cout << path << endl;return;}// 不选path += 'N';dfs();  // 递归到决策树下一层// 到这里就已经重新回到上一层了,这个时候 path 内的最后一个位置还保留了下面层的数据,需要清除掉path.pop_back();  // 回溯,恢复现场// 选path += 'Y';dfs();  // 递归到下一层path.pop_back();  // 回溯,恢复现场
}int main()
{cin >> n;dfs();return 0;
}

2. 组合型枚举 ⭐

P10448 组合型枚举 - 洛谷

【题目描述】

1∼n1 \sim n1nnnn 个整数中随机选出 mmm 个,输出所有可能的选择方案。

【输入格式】

两个整数 n,mn, mn,m ,在同一行用空格隔开。

【输出格式】

按照从小到大的顺序输出所有方案,每行 111 个。

首先,同一行内的数升序排列,相邻两个数用一个空格隔开。

其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面(例如 1 3 5 7 排在 1 3 6 8 前面)。

【示例一】

输入

5 3

输出

1 2 3 
1 2 4 
1 2 5 
1 3 4 
1 3 5 
1 4 5 
2 3 4 
2 3 5 
2 4 5 
3 4 5

【说明/提示】

对于所有测试数据满足 0≤m≤n0 \le m \le n0mn , $ n+(n-m) \le 25 $。


(1) 解题思路

首先画出决策树:

注意到在这道题中,由于我们需要枚举的是升序的序列,每一层枚举的时候是从前一个位置数字的下一个数字开始枚举的,因此在 dfs() 函数中,我们需要知道当前层我们应该从哪里开始枚举

请添加图片描述

(2) 代码实现

#include<iostream>
#include<vector>using namespace std;vector<int> path;  // 记录递归过程
int n, m;// 从 begin 位置开始往后枚举
void dfs(int begin)
{if(path.size() == m)  // 结束条件{for(auto e : path) cout << e << " ";cout << endl;return;}for(int i = begin; i <= n; i++){path.push_back(i); dfs(i + 1);  // 下一层就从当前位置填的这个数的下一个数开始枚举path.pop_back();  // 恢复现场}
}int main()
{cin >> n >> m;dfs(1);return 0;
}

3. 枚举排列 ⭐

【题目链接】

B3623 枚举排列(递归实现排列型枚举) - 洛谷

【题目描述】

今有 nnn 名学生,要从中选出 kkk 人排成一列拍照。

请按字典序输出所有可能的排列方式。

【输入格式】

仅一行,两个正整数 n,kn, kn,k

【输出格式】

若干行,每行 kkk 个正整数,表示一种可能的队伍顺序。

【示例一】

输入

3 2

输出

1 2
1 3
2 1
2 3
3 1
3 2

【说明/提示】

对于 100%100\%100% 的数据,1≤k≤n≤101\leq k\leq n \leq 101kn10


(1) 解题思路

首先画出决策树:

递归函数主体部分的逻辑就是在枚举 1, 2, 3 这三个数,所以我们只需要写一个 for 循环枚举 1 ~ n 即可。重点是我们不能选择已经选过的数字,也就是说我们需要剪枝。如何实现剪枝呢?我们可以搞一个 vis 数组,它的第 i 个位置代表 i 这个数有没有被选择过,在我们枚举的过程中只需要在 vis 数组中看一下当前位置的是否被选择过即可,如果被选择过那么 continue,否则请添加图片描述
就正常执行。


(2) 代码实现

#include<iostream>
#include<vector>using namespace std;const int N = 15;vector<int> path;
bool vis[N];  // 标记哪些数已经被选择了
int n, m;void dfs()
{if(path.size() == m){for(auto e : path) cout << e << " ";cout << endl;return;}for(int i = 1; i <= n; i++){if(!vis[i])  // 如果当前数没有被选择{path.push_back(i);vis[i] = true;  // 当前数被选择了,需要在 vis 数组中标记一下dfs();  // 递归到下一层path.pop_back();  // 恢复现场vis[i] = false;  // 恢复现场}}
}int main()
{cin >> n >> m;dfs();return 0;
}

4. 全排列问题 ⭐

【题目链接】

P1706 全排列问题 - 洛谷

【题目描述】

按照字典序输出自然数 111nnn 所有不重复的排列,即 nnn 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。

【输入格式】

一个整数 nnn

【输出格式】

1∼n1 \sim n1n 组成的所有不重复的数字序列,每行一个序列。

每个数字保留 555 个场宽。

【示例一】

输入

3

输出

	1    2    31    3    22    1    32    3    13    1    23    2    1

【说明/提示】

1≤n≤91 \leq n \leq 91n9


(1) 解题思路

首先画出决策树:

解法同【枚举排列】,唯一不同的是递归出口不同。


(2) 代码实现

请添加图片描述

#include<iostream>
#include<vector>using namespace std;const int N = 10;int n;
vector<int> path;
bool vis[N];void dfs()
{if(path.size() == n){for(auto e : path) cout << "    " << e;cout << endl;return;}for(int i = 1; i <= n; i++){if(!vis[i])  // 如果当前数没有被选择{path.push_back(i);vis[i] = true;dfs();  // 递归到下一层path.pop_back();  // 恢复现场vis[i] = false;  // 恢复现场}}
}int main()
{cin >> n;dfs();return 0;
}

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

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

相关文章

Node.js异步编程——async/await实现

一、async/await基础语法 在Node.Js编程中,async关键字用于定义异步函数,这个异步函数执行完会返回一个Promise对象,异步函数的内部可以使用await关键字来暂停当前代码的继续执行,直到Promise操作完成。 在用法上,async关键字主要用于声明一个异步函数,await关键字主要…

搭建一个简单的Agent

准备本案例使用deepseek&#xff0c;登录deepseek官网&#xff0c;登录账号&#xff0c;充值几块钱&#xff0c;然后创建Api key可以创建虚拟环境&#xff0c;python版本最好是3.12&#xff0c;以下是文件目录。test文件夹中&#xff0c;放一些txt文件做测试&#xff0c;main.p…

uv,下一代Python包管理工具

什么是uv uv&#xff08;Universal Virtual&#xff09;是由Astral团队&#xff08;知名Python工具Ruff的开发者&#xff09;推出的下一代Python包管理工具&#xff0c;使用Rust编写。它集成了包管理、虚拟环境、依赖解析、Python版本控制等功能&#xff0c;它聚焦于三个关键点…

单片机的输出模式推挽和开漏如何选择呢?

推挽和开漏是单片机的输出模式&#xff0c;属于I/O口配置的常见类型。开漏&#xff08;Open-Drain&#xff09;和推挽&#xff08;Push-Pull&#xff09;是两种根本不同的输出电路结构&#xff0c;理解它们的区别是正确使用任何单片机&#xff08;包括51和STM32&#xff09;GPI…

java18学习笔记-Simple Web Server

408:Simple Web Server Python、Ruby、PHP、Erlang 和许多其他平台提供从命令行运行的开箱即用服务器。这种现有的替代方案表明了对此类工具的公认需求。 提供一个命令行工具来启动仅提供静态文件的最小web服务器。没有CGI或类似servlet的功能可用。该工具将用于原型设计、即…

深度解析Atlassian 团队协作套件(Jira、Confluence、Loom、Rovo)如何赋能全球分布式团队协作

无穷无尽的聊天记录、混乱不堪的文档、反馈信息分散在各个不同时区……在全球分布式团队中开展真正的高效协作&#xff0c;就像是一场不可能完成的任务。 为什么会这样&#xff1f;因为即使是最聪明的团队&#xff0c;也会遇到类似的障碍&#xff1a; 割裂的工作流&#xff1a…

理解AI 智能体:智能体架构

1. 引言 智能体架构&#xff08;agent architecture&#xff09;是一份蓝图&#xff0c;它定义了AI智能体各组件的组织方式和交互机制&#xff0c;使智能体能够感知环境、进行推理并采取行动。本质上&#xff0c;它就像是智能体的数字大脑——整合了“眼睛”&#xff08;传感器…

Spring Cloud系列—SkyWalking链路追踪

上篇文章&#xff1a; Spring Cloud系列—Seata分布式事务解决方案TCC模式和Saga模式https://blog.csdn.net/sniper_fandc/article/details/149947829?fromshareblogdetail&sharetypeblogdetail&sharerId149947829&sharereferPC&sharesourcesniper_fandc&…

机器人领域的算法研发

研究生期间学习大模型&#xff0c;可投递机器人领域的算法研发、技术支持等相关岗位&#xff0c;以下是具体推荐&#xff1a; AI算法工程师&#xff08;大模型方向-机器人应用&#xff09;&#xff1a;主要负责大模型开发与优化&#xff0c;如模型预训练、调优及训练效率提升等…

深度学习入门:神经网络

文章目录一、深度学习基础认知二、神经网络核心构造解析2.1 神经元的基本原理2.2 感知器&#xff1a;最简单的神经网络2.3 多层感知器&#xff1a;引入隐藏层解决非线性问题2.3.1 多层感知器的结构特点2.3.2 偏置节点的作用2.3.3 多层感知器的计算过程三、神经网络训练核心方法…

mysql的索引有哪些?

1. 主键索引&#xff08;PRIMARY KEY&#xff09;主键索引通常在创建表时定义&#xff0c;确保字段唯一且非空&#xff1a;-- 建表时直接定义主键 CREATE TABLE users (id INT NOT NULL,name VARCHAR(50),PRIMARY KEY (id) -- 单字段主键 );-- 复合主键&#xff08;多字段组合…

【计算机视觉与深度学习实战】08基于DCT、DFT和DWT的图像变换处理系统设计与实现(有完整代码python3.13可直接粘贴使用)

1. 引言 数字图像处理作为计算机视觉和信号处理领域的重要分支,在过去几十年中得到了快速发展。图像变换技术作为数字图像处理的核心技术之一,为图像压缩、特征提取、去噪和增强等应用提供了强有力的数学工具。离散余弦变换(Discrete Cosine Transform, DCT)、离散傅里叶变…

使用Python实现DLT645-2007智能电表协议

文章目录&#x1f334;通讯支持&#x1f334; 功能完成情况服务端架构设计一、核心模块划分二、数据层定义三、协议解析层四、通信业务层&#xff08;以DLT645服务端为例&#xff09;五、通信层&#xff08;以TCP为例&#xff09;使用例子&#x1f334;通讯支持 功能状态TCP客…

未来已来:基于IPv6单栈隔离架构的安全互联实践报告

未来已来&#xff1a;基于IPv6单栈隔离架构的安全互联实践报告 报告摘要 随着IPv4地址资源彻底枯竭&#xff0c;全球网络基础设施正加速向IPv6单栈&#xff08;IPv6-Only&#xff09;演进。传统“IPv4为主、IPv6为辅”的双栈模式已无法满足数字化转型对海量地址、端到端连接与原…

Ubuntu24.04 安装 Zabbix

Ubuntu24.04 安装 Zabbix 环境&#xff1a; 软件版本Ubuntu24.04.3Nginx1.24.0MySQL8.4.6PHP8.3.6phpMyAdmin5.2.2Zabbix7.4.1 LNMP 1. 更新本地软件包索引并升级已安装软件 更新可用软件包列表 把已安装的软件升级到最新版 安装常用工具 sudo apt update && sud…

【动手学深度学习】6.2. 图像卷积

目录6.2. 图像卷积1&#xff09;互相关运算2&#xff09;卷积层3&#xff09;图像中目标的边缘检测4&#xff09;学习卷积核5&#xff09;互相关与卷积6&#xff09;特征映射和感受野7&#xff09;小结. 6.2. 图像卷积 卷积神经网络的设计是用于探索图像数据&#xff0c;本节…

游戏引擎中的Billboard技术

一.视觉公告板为解决场景中Mesh网格面数过多问题,使用2D平面Mesh替换为3D平面Mesh的技术即为Billboard技术.常用于场景中植被,树叶,粒子系统等对面数有要求的场景.二.Billboard着色器实现着色器输入参数:摄像机坐标,网格坐标,摄像机观察方向着色器输出:实际2D平面随视角不变

vue-admin-template权限管理

在基于 vue-admin-template 实现权限管理时&#xff0c;通常需要结合角色权限模型和动态路由机制&#xff0c;以满足不同用户角色对页面访问权限的控制需求。分为路由页面权限和按钮权限&#xff1a;下面是具体实现思路的思维导图和具体代码流程&#xff1a;0.实现逻辑思维导图…

微信小程序,事件总线(Event Bus) 实现

1、util.js文件/*** 事件总线*/ function createEventBus() {// 私有事件存储对象&#xff0c;通过闭包保持私有性const events {};return {/*** 监听事件&#xff0c;只执行一次* param {string} eventName - 事件名称* param {Function} callback - 回调函数*/once(eventNam…

OpenCV结构光三维重建类cv::structured_light::GrayCodePattern

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::structured_light::GrayCodePattern 是 OpenCV 库中用于结构光三维重建 的一个类&#xff0c;属于 OpenCV 的 structured_light 模块。 它用于…