算法---回溯(正文)

1.什么是回溯?

回溯算法的定义就是和暴力枚举一样枚举所有可能并加撤回,也能和暴力一样去掉一些重复(在之前就被筛出,但还要枚举这个,我们可以跳过这个了---------这个就是回溯剪枝)。但为什么回溯不是暴力呢?----这个问题大家可以先想想最后我在说。

其实回溯也是递归,如果你熟悉树状图的话,你会发现回溯的枚举过程就是一个树,而递归呢也是一棵树在这里插入图片描述

2.“回溯”该怎么做?

回溯顾名思义就是撤回,走到头也要像递归一样终止(如果到头的结果对了储藏答案反之否)。如果没走到头则产生多个子节点继续探索。
根据上面的解释回溯的代码应为

void dfs(变量){if(终止条件){存放结果 return ; //结束 }枚举所有可行 
}

当然这是最基本的模版,并没用到回溯
下面是标准模板

int flag[105];//标记 1 yes 2 no
void dfs(变量){if(终止条件){if(判断是否存放结果){存放 }return ;} for(枚举){if(flag[i]==0)   //判断是否被标记过{flag[i]=1; //标记 存放数据 dfs(变量+1);flag[i]=0; //回溯 } } 
} 

3.回溯经典问题

全排列

输入正整数N,输出由1到N这N个数(N<=7)的所有排列,每行一个排列,数与数之间有一个空格,两个排列中,第一个数小的优先输出,第一个数相同,比较第二个数,后面以此类推。

输入
正整数N

输出
所有排列

样例
输入 1
3
输出 1
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
【分析】题目比较简单,模板一带就行

#include<bits/stdc++.h>
using namespace std;
int n;
int a[105],flag[105];
void dfs(int dep){   //判断到第几层了if(dep==n+1){   for(int i=1;i<=n;i++){  //输出cout<<a[i]<<" ";}cout<<"\n";return ;}for(int i=1;i<=n;i++){if(flag[i]!=1){flag[i]=1;a[dep]=i;dfs(dep+1);flag[i]=0;  //回溯}}
} 
int main(){
cin>>n;
dfs(1);return 0;
}

组合数的拆分

【题目描述】
排列与组合是常用的数学方法,其中组合就是从n个元素中抽出r个元素(不分顺序且r≤n),我们可以简单地将n个元素理解为自然数1,2,…,n,从中任取r个数。

现要求你用递归的方法输出所有组合。

例如n=5,r=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

【输入】
一行两个自然数n、r(1<n<21,1≤r≤n)。

【输出】
所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,每个元素占三个字符的位置,所有的组合也按字典顺序。

【输入样例】
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
【分析】与全排列只能说如出一辙,只需注意排序顺序

int ab[30];
int flag[30];
int n,r;
void dfs(int dep,int last){   //底几层   上一个数+1是啥if(dep == r+1){for(int i = 1 ; i < dep ; i++){cout << setw(3) << ab[i];}cout << "\n";return ;}for(int i = last ; i <= n ; i++){  //从上一个数+1开始枚举if(flag[i] == 0){flag[i] = 1;ab[dep] = i;dfs( dep+1 , i+1 );flag[i] = 0;}}
}
int main()
{
cin >> n >> r;
dfs(1,1);return 0;
}

LETTERS

【题目描述】
给出一个row×col
的大写字母矩阵,一开始的位置为左上角,你可以向上下左右四个方向移动,并且不能移向曾经经过的字母。问最多可以经过几个字母。

【输入】
第一行,输入字母矩阵行数R
和列数S
,1≤R,S≤20

接着输出R
行S
列字母矩阵。

【输出】
最多能走过的不同字母的个数。

【输入样例】
3 6
HFDFFB
AJHGDH
DGAGEH
【输出样例】
6
【分析】这个题目是回溯+递归(深搜),不过难度不大有方向数组就行

#include<bits/stdc++.h>
using namespace std;
int row,col; 
char ab[25][25];
int flag[27];
int dx[]={0,0,-1,1}; //方向数组
int dy[]={1,-1,0,0};
int rc[25][25],cnt=0;
void dfs(int x,int y,int ans){  //当前位置    探索了多少cnt=max(ans,cnt);for(int i=0;i<4;i++){int xd=dx[i]+x;int yd=dy[i]+y;if(flag[int(ab[xd][yd]-'A')]==0&&rc[xd][yd]==0&&xd>=1&&xd<=row&&yd>=1&&yd<=col){flag[int(ab[xd][yd]-'A')]=1;rc[xd][yd]=1;dfs(xd,yd,ans+1);flag[int(ab[xd][yd]-'A')]=0;  //回溯rc[xd][yd]=0;}}return;
}
int main()
{
cin>>row>>col;
for(int i=1;i<=row;i++){for(int j=1;j<=col;j++){cin>>ab[i][j];}
}
flag[int(ab[1][1]-'A')]=1; //刚开始的被探索过了
rc[1][1]=1;
dfs(1,1,1);
cout<<cnt;return 0;
}

N皇后

在8*8国际象棋盘上,放置8个皇后,使得任意两个皇后都不会互相攻击,一共有多少种摆法?这就是著名的8皇后问题。

现在我们来尝试,在N*N的棋盘上,放置N个皇后,使得它们不会互相攻击。

皇后的走子规则是,沿着横、竖、两条对角线方向可以走任意步数。

输入
1个整数N

输出
一个整数,表示N皇后的不同解答个数

样例
输入 1
8
输出 1
92
5<=n<=9
【分析】毋庸置疑回溯,他要判断三项,那我们想,我们是不是可以不用关行了,因为我们可以枚举每一行,然后可以用回溯解决列,那斜线呢,当然也能拿数组去回溯。可是当你去回溯时,怎么做呢?
我们不妨句例子下
4皇后
(1,1)(1,2)(1,3)(1,4)
(2,1)(2,2)(2,3)(2,4)
(3,1)(3,2)(3,3)(3,4)
(4,1)(4,2)(4,3)(4,4)
当我们打上正反斜线,发现什么了?每个斜线上的各店的x+y互相相等----正斜线
每个斜线上的x与y的差(abs(x-y))互相相等----反斜线
所以我们可以用俩个数组标记俩斜线

#include<bits/stdc++.h>
using namespace std;
int n;
int lie[12],ans,xie1[100],xie2[100]; //标记数组
void dfs(int dep){if(dep==n+1){ans++;return ;} for(int i=1;i<=n;i++){if(lie[i]==0&&xie1[dep+i]==0&&xie2[dep-i+10]==0){  //如果dep-i<0,+10会让dep-i>0因为n<=9lie[i]=1;xie1[dep+i]=1;xie2[dep-i+10]=1;dfs(dep+1);lie[i]=0;xie1[dep+i]=0;xie2[dep-i+10]=0;}}
}
int main()
{
cin>>n;
dfs(1);
cout<<ans;return 0;
}

造素数

现在给你n个数,你需要从中选出m个数,使得这m个数的和为素数,求出可选的方案数。

输入
第一行两个整数n和m。

第二行n个整数,表示可选的数字。

输出
输出有多少种方案可以使得选出的数之后为素数。

样例
输入 1
3 2
1 2 3

输出 1
2

输入 2
3 1
2 2 2
输出 2
3
这里不做分析了原理同组合数的拆分

#include<bits/stdc++.h>
using namespace std;
int n,m,ans;
int a[105],b[105];
bool isprime(int n){if(n==1) return false;for(int i=2;i*i<=n;i++){if(n%i==0) return false;}return true;
}
void dfs(int cnt,int now){if(now==n+1){if(cnt==m){int k=0;for(int i=0;i<cnt;i++){k+=b[i];}if(isprime(k)){ans++;}}return ;}b[cnt]=a[now];dfs(cnt+1,now+1); //选dfs(cnt,now+1); //不选
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
dfs(0,1);
cout<<ans<<"\n";return 0;
}

最后解答一下开始时的问题
在这几个例题中,相信大家已经看出来了暴力需要好几层,而虽然回溯也是和暴力差不多的时间复杂度可是却可以用少量代码解决要几个for才能解决的问题(有的时候也是解决不了的如LETTERS)

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Python实现文本情感分析

前言 文本情感分析是一种重要的自然语言处理(NLP)任务&#xff0c;旨在从文本数据中推断出情感信息&#xff0c;例如正面、负面或中性情感。它在社交媒体分析、产品评论、市场调研等领域都有广泛的应用。本文将详细介绍如何使用Python进行文本情感分析&#xff0c;包括基础概念…

【从零开始学设计模式】第四章_抽象工厂模式(与工厂方法模式区分)

第四章_抽象工厂模式&#xff08;与工厂模式区分&#xff09; 1.介绍 1.1定义 为访问类提供一个创建一组相关或相互依赖对象的接口&#xff0c;且访问类无须指定所要产品的具体类 就能得到同族的不同等级的产品的模式结构&#xff1b; 1.2解决的问题 主要解决接口选择的问…

解析十六进制雷达数据格式:解析雷达数据类型。

以Cat62格式雷达数据为例&#xff0c;十六进制雷达数据部分代码&#xff1a; 3e0120bf7da4ffee0085 雷达数据使用2个字符&#xff08;1个字节&#xff09;标识&#xff0c;在这里是“3e”&#xff0c;转换为十进制数为62。 雷达数据类型父类&#xff1a; base_header_process…

Git简单了解

文章目录 1、Git概述2、Git下载与安装3、Git代码托管服务3.1、使用码云托管服务 1、Git概述 什么是Git Git是一个分布式版本控制工具&#xff0c;主要用于管理开发过程中的源代码文件&#xff08;Java类、xml文件、html页面等&#xff09;&#xff0c;在软件开发过程中被广泛使…

jvm问题自查思路

本文聊一下最近处理了一些jvm的问题上&#xff0c;将这个排查和学习过程分享一下&#xff0c;看了很多资料&#xff0c;最终都会落地到几个工具的使用&#xff0c;本文主要是从文档学习、工具学习和第三方技术验证来打开认知和实践&#xff0c;希望有用。 一、文档 不仅知道了…

新年新展望

去年其实是收获颇丰的一年&#xff0c;除了工作中各项工作都得到了很大的推进&#xff0c;个人生活中也有很多变化&#xff0c;其中还拿到了功能安全工程师的证书&#xff0c;以及功能安全经理的证书。 展望一下2024年准备输出的内容&#xff0c;一个是对ISO26262的解读&#x…

力扣刷题之旅:进阶篇(五)—— 动态规划(DP)的妙用

力扣&#xff08;LeetCode&#xff09;是一个在线编程平台&#xff0c;主要用于帮助程序员提升算法和数据结构方面的能力。以下是一些力扣上的入门题目&#xff0c;以及它们的解题代码。 --点击进入刷题地址 引言&#xff1a; 在算法的世界中&#xff0c;动态规划&#xff…

开发JSP应用程序

开发JSP应用程序 问题陈述 TecknoSoft Pvt Ltd.公司的首席技术官(CTO)John Barrett将创建一个应用程序的任务委托给了开发团队,该应用程序应在客户访问其账户详细信息前验证其客户ID和密码。客户ID应是数字形式。John希望如果所输入的客户ID或密码不正确,应向客户显示错误…

一文带你读懂JSON模块

json模块 JSON (JavaScript Object Notation)&#xff1a;是一个轻量级的数据交换格式模块&#xff0c;受javascript对象文本语法启发&#xff0c;但不属于JavaScript的子集。 常用方法&#xff1a; dump(obj,fp)&#xff1a;将对象以字符串的形式写入文件中。 load(fp)&am…

Web项目利用EasyExcel实现Excel的导出操作

早期Java使用的一些解析&#xff0c;到处excel的框架存在种种问题被遗弃&#xff0c;现在使用阿里巴巴所提供的EasyExcel已成为一种主流&#xff0c;本篇将详细介绍该功能在Web项目中如何实际应用。 详细操作文档&#xff1a;写Excel | Easy Excel 一、项目演示 在后台管理界…

【数据结构与算法-初学者指南】【附带力扣原题】队列

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《数据结构与算法&#xff1a;初学者入门指南》&#x1f4d8;&am…

作业2.8

1、选择题 1.1、以下选项中,不能作为合法常量的是 ____B______ A&#xff09;1.234e04 B&#xff09;1.234e0.4 C&#xff09;1.234e4 D&#xff09;1.234e0 1.2、以下定义变量并初始化错误的是_____D________。 A) char c1 ‘H’ &#xff1b; B) char c…

《MySQL 简易速速上手小册》第9章:高级 MySQL 特性和技巧(2024 最新版)

文章目录 9.1 使用存储过程和触发器9.1.1 基础知识9.1.2 重点案例&#xff1a;使用 Python 调用存储过程实现用户注册9.1.3 拓展案例 1&#xff1a;利用触发器自动记录数据更改历史9.1.4 拓展案例 2&#xff1a;使用 Python 和触发器实现数据完整性检查 9.2 管理和查询 JSON 数…

【黑马程序员】程序的内存模型

文章目录 内存分区模型分区意义代码区全局区特点代码示例 栈区特点代码示例 堆区特点代码示例 new 操作符 20240209 内存分区模型 分区意义 不同区域存放的数据&#xff0c;赋予不同的生命周期&#xff0c;给我们更大的灵活编程 代码区 处于程序未执行之前 程序编译后生成的…

文件绕过-Unsafe Fileuoload

文件上传基础 什么是文件上传 将客户端数据以文件形式封装通过网络协议发送到服务器端&#xff0c;在服务器端解析数据&#xff0c;最终在服务端硬盘上作为真实的文件保存。 通常一个文件以HTTP协议进行上传时&#xff0c;将以POST请求发送至Web服务器&#xff0c;Web服务器…

PWM输入输出

PWM&#xff08;Pulse Width Modulation&#xff09;即脉冲宽度调制&#xff0c;在具有惯性的系统中&#xff0c;可以通过对一系列脉冲的宽度进行制&#xff0c;来等效地获得所需要的模拟参量&#xff0c;常应用于电机控速、开关电源等领域。 PWM参数 PWM 中有三个重要参数&…

C++11新特性(一)

目录 C11简介 统一的列表初始化 变量类型推导 std::initializer_list 声明 auto decltype nullptr STL的一些变化 右值引用 右值引用和左值引用 右值引用适用场景 移动构造和移动语义 对类的影响 可变参数模板 递归函数方式展开参数包 STL容器中的empalce相…

内存管理 | 进程地址空间

文章目录 1.进程地址空间的理解2.将虚拟地址转换为物理地址3.进程地址空间的设计4.进程地址空间的好处 1.进程地址空间的理解 在 前文 分享的fork创建子进程的系统调用中&#xff0c;一个变量接收了两个不同的返回值&#xff01;通过推测也知道&#xff0c;那个地址绝不是真是…

基于SpringBoot的记账系统项目

点击以下链接获取源码&#xff1a;https://download.csdn.net/download/qq_64505944/88822660?spm1001.2014.3001.5503 Java项目-8 开发工具&#xff1a;IDEA/Eclipse,MySQL,Tomcat 项目框架&#xff1a;SpringBoot,layui 功能&#xff1a;可以按照类型和时间查询&#xff0c…

融资项目——获取树形结构的数据

如下图所示&#xff0c;下列数据是一个树形结构数据&#xff0c;行业中包含若干子节点。表的设计如下图&#xff0c;设置了一个id为1的虚拟根节点。&#xff08;本树形结构带虚拟根节点共三层&#xff09; 实现逻辑&#xff1a; 延时展示方法&#xff0c;先展现第二层的信息&a…