当前位置: 首页 > news >正文

NO.71十六届蓝桥杯备战|搜索算法-递归型枚举与回溯剪枝|枚举子集|组合型枚举|枚举排列|全排列问题(C++)

  1. 什么是搜索?
    搜索,是⼀种枚举,通过穷举所有的情况来找到最优解,或者统计合法解的个数。因此,搜索有时候也叫作暴搜。
    搜索⼀般分为深度优先搜索(DFS)与宽度优先搜索(BFS)。
  2. 深度优先遍历vs深度优先搜索,宽度优先遍历vs宽度优先搜索
    遍历是形式,搜索是⽬的。
    不过,在⼀般情况下,我们不会去纠结概念的差异,两者可以等同。
  3. 回溯与剪枝
  • 回溯:当在搜索的过程中,遇到⾛不通或者⾛到底的情况时,就回头。
  • 剪枝:剪掉在搜索过程中,剪掉重复出现或者不是最优解的分⽀
    搜索的本质:对决策树来一次遍历,直到把所有的情况全部收集到
递归型枚举与回溯剪枝初识
  1. 画决策树;
  2. 根据决策树写递归
B3622 枚举子集(递归实现指数型枚举) - 洛谷

设⼀共有3个数,分别是1,2,3。「从前往后」考虑每⼀个数,针对当前这个数「选」或者「不选」
![[Pasted image 20250406205715.png]]

设计递归函数:

  • 重复⼦问题:针对某⼀位,「选」或者「不选」这个数。因为最终结果要按照「字典序」输出,我们可以「先考虑不选」,然后「再考虑选」;
  • 实现⽅式参考代码和注释,结合「决策树」⼀起看会很清晰
#include <bits/stdc++.h>
using namespace std;

int n;
string path;

void dfs(int pos)
{
    if (pos > n)
    {
        //path存着前n个人的决策
        cout << path << endl;
        return;
    }

    //不选
    path += 'N';
    dfs(pos+1);
    path.pop_back(); //回溯,清空现场
    //选
    path += 'Y';
    dfs(pos+1);
    path.pop_back(); //回溯,清空现场
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n;

    dfs(1);
    
    return 0;
}
P10448 组合型枚举 - 洛谷

设n = 4, m = 3 ,「从前往后」考虑3 个位置应该选哪个数,我们可以画出如下决策树
![[Pasted image 20250406210154.png]]

设计递归函数:

  • 重复⼦问题:当前这⼀位,应该放哪个数上去。因为这是⼀个「组合」问题,不涉及排列,所以我们当前位置开始放的数,应该是「上次决策的数的下⼀位」
  • 实现⽅式参考代码和注释,结合「决策树」⼀起看会很清晰。
#include <bits/stdc++.h>
using namespace std;

int n, m;
vector<int> path;

void dfs(int pos, int begin)
{
    if (pos > m)
    {
        for (auto x : path) cout << x << " ";
        cout << endl;
        return;
    }
    
    for (int i = begin; i <= n; i++)
    {
        path.push_back(i);
        dfs(pos+1, i+1);
        path.pop_back();
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n >> m;

    dfs(1, 1);
    
    return 0;
}
#include <bits/stdc++.h>
using namespace std;

int n, m;
vector<int> path;

void dfs(int begin)
{
    if (path.size() == m)
    {
        for (auto x : path) cout << x << " ";
        cout << endl;
        return;
    }
    
    for (int i = begin; i <= n; i++)
    {
        path.push_back(i);
        dfs(i+1);
        path.pop_back();
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n >> m;

    dfs(1);
    
    return 0;
}
B3623 枚举排列(递归实现排列型枚举) - 洛谷

设n = 3, k = 2 ,⼀共要选出两个数,可以依次「考虑要选出来的数」是谁,画出如下决策树
![[Pasted image 20250406212841.png]]

设计递归函数:

  • 重复⼦问题:考虑这⼀位要放上什么数。因为是「排列」问题,所以我们直接从1开始枚举要放的数。
  • 剪枝:在这⼀条路径中,我们「不能选择之前已经选择过的数」。
  • 实现⽅式参考代码和注释,结合「决策树」⼀起看会很清晰
#include <bits/stdc++.h>
using namespace std;

const int N = 15;

int n, k;
vector<int> path;
bool st[N]; //标记选过的数

void dfs()
{
    if (path.size() == k)
    {
        for (auto x : path) cout << x << " ";
        cout << endl;
        return;
    }

    for (int i = 1; i <= n; i++)
    {
        if (st[i]) continue;
        path.push_back(i);
        st[i] = true;
        dfs();
        //恢复现场
        path.pop_back();
        st[i] = false;
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n >> k;
    
    dfs();
    
    return 0;
}
P1706 全排列问题 - 洛谷

跟上⼀道题的决策⼀样,我们可以枚举每⼀位应该放上什么数,只不过少了k的限制。剪枝的策略还是⼀样的,那就是在路径中,「不能选择之前已经选过的数」

#include <bits/stdc++.h>
using namespace std;

const int N = 15;

int n;
vector<int> path;
bool st[N];

void dfs()
{
    if (path.size() == n)
    {
        for (auto x : path)
        {
            printf("%5d", x);        
        }
        cout << endl;
        return;
    }

    for (int i = 1; i <= n; i++)
    {
        if (st[i]) continue;
        path.push_back(i);
        st[i] = true;
        dfs();
        path.pop_back();
        st[i] = false;
    }
}

int main()
{
    cin >> n;

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

相关文章:

  • SpringBoot自动装配原理---Spring
  • import cv2 安装失败
  • 语法: value=label_address( label);
  • PyTorch池化层详解:原理、实现与示例
  • ctf-show-micsx
  • 【Kubernetes】StorageClass 的作用是什么?如何实现动态存储供应?
  • TLS 1.2 握手过程,每个阶段如何保证通信安全?​​
  • 古诗词数据集(74602条简体版、繁体版) | 智能体知识库 | AI大模型训练
  • iOS APP集成Python解释器
  • OpenCV 在树莓派上进行实时人脸检测
  • C++ 内存访问模式优化:从架构到实践
  • Redis之布隆过滤器
  • Unity3D仿星露谷物语开发34之单击Drop项目
  • 算法思想之滑动窗口(一)
  • 人脸专注度检测系统(课堂专注度检测、人脸检测、注意力检测系统)
  • 【C++】第九节—string类(中)——详解+代码示例
  • JVM深入原理(六)(一):JVM类加载器
  • 基于51单片机和8X8点阵屏、独立按键的双人弹球小游戏
  • 智能气候:AI Agent结合机器学习与深度学习在全球气候变化驱动因素预测中的应用
  • 区块链日记6 - Solana入门 - PDA增删改查数据1
  • 【数据结构】并查集应用
  • 面试可能会遇到的问题回答(编程语言部分)
  • 清晰易懂的 HeidiSQL 安装教程
  • 第四章:透明多级分流系统_《凤凰架构:构建可靠的大型分布式系统》
  • JavaScript基础--12-基本包装类型
  • C++堆,栈,静态成员及使用准则
  • lib-zo,C语言另一个协程库,dns协程化, gethostbyname
  • 解决 PDF 难题:批量处理、文档清理与自由拆分合并
  • 力扣经典算法篇-9-跳跃游戏(贪心算法,反向递推)
  • Debezium嵌入式连接postgresql封装服务