回溯算法2s总结

8.回溯算法

回溯算法理论基础

回溯法也可以叫做回溯搜索法,它是一种搜索的方式。回溯是递归的副产品,只要有递归就会有回溯。

回溯的本质是穷举,穷举所有可能,然后选出我们想要的答案

回溯法解决的问题

回溯法,一般可以解决如下几种问题:

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

组合是不强调元素顺序的,排列是强调元素顺序

如何理解回溯法

回溯法解决的问题都可以抽象为树形结构

因为回溯法解决的都是在集合中递归查找子集,集合的大小就构成了树的宽度,递归的深度就构成了树的深度

递归就要有终止条件,所以必然是一棵高度有限的树(N叉树)。

回溯法套路总结

回溯三部曲

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

在回溯算法中,我的习惯是函数起名字为backtracking,这个起名大家随意。

回溯算法中函数返回值一般为void。

回溯算法需要的参数可不像二叉树递归的时候那么容易一次性确定下来,所以一般是先写逻辑,然后需要什么参数,就填什么参数。

void backtracking(参数)
  • 回溯函数终止条件

遍历树形结构一定有终止条件,回溯也有。什么时候达到了终止条件,树中就可以看出,一般来说搜到叶子节点了,也就找到了满足条件的一条答案,把这个答案存放起来,并结束本层递归。

if (终止条件) {
    存放结果;
    return;
}
  • 回溯搜索的遍历过程

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

回溯算法理论基础

特意举例集合大小和孩子的数量是相等的!

回溯函数遍历过程伪代码如下:

for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
    处理节点;
    backtracking(路径,选择列表); // 递归
    回溯,撤销处理结果
}

for循环就是遍历集合区间,可以理解一个节点有多少个孩子,这个for循环就执行多少次。

backtracking这里自己调用自己,实现递归。

大家可以从图中看出for循环可以理解是横向遍历,backtracking(递归)就是纵向遍历回溯不断调整结果集。这样就把这棵树全遍历完了,一般来说,搜索叶子节点就是找的其中一个结果了。

回溯算法模板框架

分析完过程,回溯算法模板框架如下:

void backtracking(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}

剪枝优化

剪枝精髓是:for循环在寻找起点的时候要有一个范围,如果这个起点到集合终止之间的元素已经不够 题目要求的k个元素了,就没有必要搜索了

for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) // i为本次搜索的起始位置
求组合

如果是一个集合来求组合的话,就需要startIndex,如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex

那么“使用过”在这个树形结构上是有两个维度的,一个维度是同一树枝上使用过,一个维度是同一树层上使用过。没有理解这两个层面上的“使用过” 是造成大家没有彻底理解去重的根本原因。

**树层去重的话,需要对数组排序!**需要加一个bool型数组used,用来记录同一树枝上的元素是否使用过。

如果candidates[i] == candidates[i - 1] 并且 used[i - 1] == false,就说明:前一个树枝,使用了candidates[i - 1],也就是说同一树层使用过candidates[i - 1]

此时for循环里就应该做continue的操作。

其实切割问题类似组合问题

如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!

那么既然是无序,取过的元素不会重复取,写回溯算法的时候,for就要从startIndex开始,而不是从0开始!

Hjk最多几个直角三角形(我自己存在去重问题)

题目
我们手上有N条长度不等的线段,想知道我们能用这些线段组成多少个直角三角形。每条线段只能用一次,一个三角形由三条线段组成。

输入:

第一行是一个数字T,代表有T组数据。
在接下来的T行中,每一行的开始是一个数字N(代表线段的数量),后面跟着N个数字,代表每条线段的长度。
输出:

对于每一组数据,输出一行,表示我们可以组成的直角三角形数量。
示例:

输入:
1
7 3 4 5 6 5 12 13

输出:
2

#include <iostream>
#include <vector>
#include <algorithm>
#include <set>

bool isRightTriangle(int a, int b, int c) {
    std::vector<int> sides = {a, b, c};
    std::sort(sides.begin(), sides.end());
    return sides[0] * sides[0] + sides[1] * sides[1] == sides[2] * sides[2];
}

int countRightTriangles(std::vector<int>& sides) {
    int count = 0;
    int n = sides.size();
    std::vector<int> path;
    std::vector<bool> used(n, false);

    std::function<void(int)> backtrack = [&](int start) {
        if (path.size() == 3) {
            if (isRightTriangle(path[0], path[1], path[2])) {
                count++;
            }
            return;
        }

        for (int i = start; i < n; i++) {
            if (!used[i]) {  // Ensure each side is used at most once
                used[i] = true;
                path.push_back(sides[i]);
                backtrack(i + 1);
                path.pop_back();
                used[i] = false;
            }
        }
    };

    backtrack(0);
    return count;
}

int main() {
    int T;
    std::cin >> T;
    while (T--) {
        int N;
        std::cin >> N;
        std::vector<int> sides(N);
        for (int i = 0; i < N; ++i) {
            std::cin >> sides[i];
        }
        std::cout << countRightTriangles(sides) << std::endl;
    }
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

买随身WiFi快存好❗随身WiFi真的靠谱吗?随身WiFi推荐测评!随身WiFi哪个牌子靠谱?

选购随身WiFi避免众多波折&#xff0c;这篇随身WiFi购买指南&#xff0c;务请珍藏于心&#xff0c; 以备不时之需&#xff01;选购随身WiFi的三大避坑指南&#xff1a;1、基站信号稳为先&#xff1a;选择前务必细查所在地基站信 号&#xff0c;确保网络畅通无阻。 2、正规认证…

必应bing搜索广告推广国内能开户吗?

随着互联网广告市场的不断进化和细分化&#xff0c;必应Bing搜索广告已逐渐成为中国企业拓展国内市场、精准触达目标客户的重要渠道之一。2024年&#xff0c;必应Bing在国内市场的进一步布局&#xff0c;不仅彰显了其对本土企业的强大吸引力&#xff0c;更带来了全新的开户政策…

Go——面向对象

一. 匿名字段 go支持只提供类型而不写字段名的方式&#xff0c;也就是匿名字段&#xff0c;也称为嵌入字段。 同名字段的情况 所以自定义类型和内置类型都可以作为匿名字段使用 指针类型匿名字段 二.接口 接口定义了一个对象的行为规范&#xff0c;但是定义规范不实现&#xff…

利用免费AI开源引擎:实现图像识别技术在多主体检测中的应用|识别万物|本地化部署

在当今快速发展的图像处理领域&#xff0c;图像主体检测技术已成为提升图像分析效率和精度的关键工具。该技术能够自动识别和定位图像中的一个或多个主要对象&#xff0c;并提供其具体的位置坐标和分类标签。这不仅为图像编辑和优化提供了便利&#xff0c;也为后续的图像识别任…

C-开发 visual Studio扩展插件介绍-格式化插件Xaml Styler、CSharpier介绍(扩展插件安装方法)

C#开发 visual Studio扩展插件介绍 扩展插件安装方法Xaml StylerCSharpier 提高C#开发效率常用的插件 扩展插件安装方法 菜单栏点击“扩展”→“管理扩展”。 打开扩展页面 右上角搜索需要安装的插件&#xff0c;然后点击下载 安装完成后&#xff0c;根据提示关闭VS进行安…

selenium绕过网站检测的方法

使用selenium打开如下网站&#xff0c;进行检测&#xff0c;代码如下&#xff1a; from selenium import webdriver import timedriver webdriver.Chrome() driver.get(https://bot.sannysoft.com/) time.sleep(60)发现webdriver被检测到了 在这里可使用一个selenium提供的插…

【MATLAB源码-第7期】基于matlab的8PSK的实际误码率BER和理论误码率BER对比仿真。

1、算法描述 8PSK (8 Phase Shift Keying 8移相键控) 是一种相位调制算法。相位调制&#xff08;调相&#xff09;是频率调制&#xff08;调频&#xff09;的一种演变&#xff0c;载波的相位被调整用于把数字信息的比特编码到每一次相位改变&#xff08;相移&#xff09;。&quo…

是时候将 DevOps 可见性扩展到网络边缘了

尽管部署前运行了大量测试&#xff0c;但在部署应用程序后&#xff0c;性能问题经常让 DevOps 团队感到困惑。经过进一步调查&#xff0c;最常被忽视的问题是应用程序本身的分布式特性。从多个位置访问应用程序的最终用户永远不会拥有相同水平的互联网服务&#xff0c;因此在纽…

让大模型落地有“技”可循

“2018年&#xff0c;随着Transformer预训练模型的兴起&#xff0c;自然语言处理&#xff08;NLP&#xff09;学术圈中形成了一个主流观点——NLP领域的不同技术方向&#xff0c;如文本分类、文本匹配、序列标注等&#xff0c;最终都会被归结到文本生成这一核心任务之下。”这是…

【大语言模型】基础:如何处理文章,向量化与BoW

词袋模型&#xff08;BoW&#xff09;是自然语言处理&#xff08;NLP&#xff09;和机器学习中一种简单而广泛使用的文本表示方法。它将文本文档转换为数值特征向量&#xff0c;使得可以对文本数据执行数学和统计操作。词袋模型将文本视为无序的单词集合&#xff08;或“袋”&a…

【电控笔记0】稳定度判断

简要概括 现控:原理虚轴,稳定度越高 自控:相位裕度PM 增益裕度GM 开环传函 不稳定条件判断

Proteus 8 的使用记录

创建仿真文件 新建文件&#xff1a;默认下一步&#xff0c;至完成创建。 功能选择如图&#xff1a; 放置器件 常用元器件名称 keywords 常用51单片机 AT89C52 晶振 CRYSTAL 电阻 RES 排阻 RESPACK-8 瓷片电容 CAP 电解电容 CAP-ELEC 单刀单掷开关 S…

【教学类-52-01】20240411动物数独(4宫格)

作品展示 背景需求&#xff1a; 一、下载图片 PS修图&#xff08;图片长宽一样&#xff0c;把动物图片上下拉长&#xff09; 二、数独结构分析&#xff1a; 1、这是一个四宫格的数独题&#xff0c; 2、将1234换成了四种小动物图片。 于是我去找到原来做过的一个代码&#xf…

day05-java面向对象(上)

5.1 面向对象编程 5.1.1 类和对象 1、什么是类 类是一类具有相同特性的事物的抽象描述&#xff0c;是一组相关属性和行为的集合。 属性&#xff1a;就是该事物的状态信息。 行为&#xff1a;就是在你这个程序中&#xff0c;该状态信息要做什么操作&#xff0c;或者基于事物…

web安全-SSH私钥泄露

发现主机 netdiscover -r 192.168.164.0 扫描端口 看到开放80和31337端口都为http服务 浏览器访问测试 查看80端口和31337端口网页和源代码并无发现有用信息 目录扫描 扫描出80端口并无有用信息 扫描31337端口 发现敏感文件robots.txt和目录.ssh 访问敏感文件和目录 /.ss…

pugixml C++ 开发者处理 XML 数据的理想选择之一

pugixml 是一个广受好评的 C XML 解析库&#xff0c;其相对优势包括但不限于以下几个方面&#xff1a; pugixml 以其高效、易用、全面的功能和良好的跨平台能力成为 C 开发者处理 XML 数据的理想选择之一。 链接&#xff1a; 使用Pugixml库&#xff0c;轻松处理XML文件-CSDN…

vue 原理【详解】MVVM、响应式、模板编译、虚拟节点 vDom、diff 算法

vue 的设计模式 —— MVVM M —— Model 模型&#xff0c;即数据V —— View 视图&#xff0c;即DOM渲染VM —— ViewModel 视图模型&#xff0c;用于实现Model和View的通信&#xff0c;即数据改变驱动视图渲染&#xff0c;监听视图事件修改数据 初次渲染 将模板编译为 render …

Prometheus报错,查不到数据

Warning: Error fetching server time: Detected 28799.947999954224 seconds time difference between your browser and the server. Prometheus relies on accurate time and time drift might cause unexpected query results. 1.这是因为服务器和本地时间不同步导致的 查…

抖店怎么回复客户消息才能减少差评?分享几个超级实用的话术!

哈喽~我是电商月月 新手入驻抖音小店出单后&#xff0c;或多或少都会遇到差评现象 差评私信不解决&#xff0c;顾客不满意&#xff0c;店铺的体验分下降&#xff0c;差评也能被所有的顾客看见 那之后的顾客就会觉得店铺不可靠&#xff0c;那新手如何避免这一现象呢 今天我就…

SLF4J对lombok类型的对象调用toString()失败--StackOverflowError

PackingDemand.class StatusHistory.class 造成该问题的原因是&#xff1a;PackingDemand与StatusHistory之间的双向引用。这些类中生成的两个toString()方法都会无休止地相互调用导致出现java.lang.StackOverflowError。 解决方法&#xff1a; 1.对于使用ToString.Exclude生…
最新文章