算法---回溯(正文)

news2025/1/19 2:34:38

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<=9
			lie[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://www.coloradmin.cn/o/1441729.html

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

相关文章

分享90个行业PPT,总有一款适合您

分享90个行业PPT&#xff0c;总有一款适合您 90个行业PPT下载链接&#xff1a;https://pan.baidu.com/s/1bHvhk_42-IFAjNdjPPtMZw?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易…

【蓝桥杯冲冲冲】Prime Gift

【蓝桥杯冲冲冲】Prime Gift 蓝桥杯备赛 | 洛谷做题打卡day31 文章目录 蓝桥杯备赛 | 洛谷做题打卡day31Prime Gift题面翻译题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 提示题解代码我的一些话 Prime Gift 题面翻译 给你 n n n 个…

自适应二次元404页面源码

自适应二次元404页面源码&#xff0c;HTMLCSSJS,喜欢二次元的朋友可以下载使用 蓝奏云&#xff1a;https://wfr.lanzout.com/iuPNQ1ns7dxg

Linux网络编程——udp套接字

本章Gitee地址&#xff1a;udp套接字 文章目录 创建套接字绑定端口号读取数据发送数据聊天框输入框 创建套接字 #include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol);int domain参数&#xff1a;表面要创建套接字的域…

ElasticSearch之倒排索引

写在前面 本文看下es的倒排索引相关内容。 1&#xff1a;正排索引和倒排索引 正排索引就是通过文档id找文档内容&#xff0c;而倒排索引就是通过文档内容找文档id&#xff0c;如下图&#xff1a; 2&#xff1a;倒排索引原理 假定我们有如下的数据&#xff1a; 为了建立倒…

Day7.

使用QT编写一个简单QQ登录界面 widget.c #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget) {ui->setupUi(this);this->setWindowIcon(QIcon(":/pictrue/qq.png"));ui-&…

github使用问题汇总

1. Permission denied 1.1. 问题描述 Permission denied (publickey). fatal: Could not read from remote repository. 1.2. 解决方法 生成公钥 ssh-keygen -t ed25519 -C "your_emailexample.com" 点击回车三次 Generating public/private ed25519 key pair. …

从RSA角度出发解析JWT原理

文章目录 一、JWT介绍1. JWT组成部分2. 头部&#xff08;Header&#xff09;3. 载荷&#xff08;Payload&#xff09;4. 签名&#xff08;Signature&#xff09; 二、深入理解JWT签名验证1. 签名生成2. 签名验证3. 为什么JWT是安全的 三、如何验证JWT是否有效四、 Why JWT&…

【Docker进阶】镜像制作-用Dockerfile制作镜像(一)

进阶一 docker镜像制作 文章目录 进阶一 docker镜像制作用dockerfile制作镜像dockerfile是什么dockerfile格式为什么需要dockerfileDockerfile指令集合FROMMAINTAINERLABELCOPYENVWORKDIR 用dockerfile制作镜像 用快照制作镜像的缺陷&#xff1a; 黑盒不可重复臃肿 docker…

5G智能卷烟工厂数字孪生可视化平台,推进烟草行业数字化转型

5G智能卷烟工厂数字孪生可视化平台&#xff0c;推进烟草行业数字化转型。随着5G技术的不断发展&#xff0c;智能卷烟工厂数字孪生可视化平台成为了推进烟草行业数字化转型的重要手段。该平台将5G技术与数字孪生技术相结合&#xff0c;实现了对卷烟生产全过程的实时监控、数据分…

基于 Python 的漏洞扫描系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

计算机网络-流量控制(数据链路层的流量控制及与传输层流量控制的区别 流量控制的方法 可靠传输,滑动窗口,流量控制三者关系)

文章目录 数据链路层的流量控制及与传输层流量控制的区别流量控制的方法各方法对应的发生窗口和接收窗口大小 可靠传输&#xff0c;滑动窗口&#xff0c;流量控制三者关系小结 数据链路层的流量控制及与传输层流量控制的区别 端到端&#xff1a;两个主机之间的 点对点&#xf…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Slider组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之Slider组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、Slider组件 滑动条组件&#xff0c;通常用于快速调节设置值&#xff0c;如音量调…

PKI - 借助Nginx 实现Https 服务端单向认证、服务端客户端双向认证

文章目录 Openssl操系统默认的CA证书的公钥位置Nginx Https 自签证书Nginx Https 使用CA签发证书客户端使用自签证书供服务端验证客户端使用 根证书 签发客户端证书 供服务端验证 Openssl https://www.openssl.net.cn/ openssl是一个功能丰富且自包含的开源安全工具箱。 它提…

Python算法题集_删除链表的倒数第 N 个结点

Python算法题集_删除链表的倒数第 N 个结点 题19&#xff1a;删除链表的倒数第 N 个结点1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【二次遍历】2) 改进版一【快慢指针】3) 改进版二【列表裁剪】 4. 最优算法 本文为Python算法题集之一的代…

如何像工程师一样阅读 - 快速阅读技术书籍的9个技巧

0. 目的 在看了 Read Like an Engineer: 9 Tips for Reading Technical Books Fast 之后&#xff0c; 记录一些个人的看法&#xff0c;并在这篇英文文章上作为实验&#xff0c; 记录一下正确的阅读方法。 1. 第一次阅读 1.1 生词表 parcel of the job: 工作中必不可少的部分…

改变AI服务器:探索界面互连芯片技术的创新突破

根据TrendForce的数据&#xff0c;AI服务器的出货量约为130,000台&#xff0c;占全球服务器总出货量的约1%。随着微软、Meta、百度和字节跳动等主要制造商相继推出基于生成式AI的产品和服务&#xff0c;订单量显著增加。预测显示&#xff0c;在ChatGPT等应用的持续需求推动下&a…

【JAVA WEB】盒模型

目录 边框 内边距 基础写法 复合写法 外边距 基础写法 复合写法 块级元素的水平居中 弹性布局 设置行内元素的属性 &#xff0c;span 每一个HTML元素就相当于是一个矩形的“盒子” 这个盒子由以下这几个部分构成&#xff1a; 1.边框 border 2.内容 content 3.内边…

掌握Vue,开启你的前端开发之路!

介绍&#xff1a;Vue.js是一个构建数据驱动的Web应用的渐进式框架&#xff0c;它以简洁和轻量级著称。 首先&#xff0c;Vue.js的核心在于其视图层&#xff0c;它允许开发者通过简单的模板语法将数据渲染进DOM&#xff08;文档对象模型&#xff09;。以下是Vue.js的几个重要特点…

EMC学习笔记(二十三)降低EMI的PCB设计指南(三)

双层板电源分配 1.单点与多点分布2.星型分布3.创建网格平面4.旁路和磁珠5.将噪声保持在芯片附近 tips&#xff1a;资料主要来自网络&#xff0c;仅供学习使用。 1.单点与多点分布 在一个真正的单点配电系统中&#xff0c;每个有源元件都有自己独立的电源和地&#xff0c;这些…