函数难题:排列

给定一个整数 n,将数字 1∼n 排成一排,将会有很多种排列方法。

现在,请你按照字典序将所有的排列方法输出。

输入格式

共一行,包含一个整数 n。

输出格式

按字典序输出所有排列方案,每个方案占一行。

数据范围

1≤n≤9

输入样例:
3
输出样例:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

 

#include <iostream>
#include <cstdio>
using namespace std;const int N = 10;
int n;
void dfs(int u, int nums[], bool st[])
{if (u > n){for (int i = 1; i <= n; i++)printf("%d ", nums[i]);/*这里用printf和前面输入的时候用scanf,是有原因的。因为scanf和printf输入输出比cin和cout运行时间更快,会节省大量的运行时间,*/puts("");}/*这个if语句是这个递归函数里面的终止条件。当u>n时,就依次输出每一位上的数字,然后组合在一起,得到我们想要的排列结果。*/else{for (int i = 1; i <= n; i++)/*不管你要做什么,都是在遍历数字的基础上面操作的,然后再筛选数字那些,所以这个for循环是必要的。*/{//下面的语句我一句一句说。if (!st[i])/*这个判断条件的意思时,如果数字没有被使用过的话,就可以进入这个if语句。*/{st[i] = true;nums[u] = i;dfs(u + 1, nums, st);/*这里先说上面那三句语句。我们还是老样子,按照逻辑来写代码,按照自己的思路来走,而且我们只需要利用一个结果来推全部,这样写和理解起来都要容易些。首先,是要没被使用过的数字才能进这个if语句。然后我们观察示例结果1 2 3,我们发现这第一个排列的结果1 2 3 他每一位上的数字是没有重复的。那么我们就以这个为思路去写。*//*首先,1是没有被用过的,因为刚开始初始化的时候1是false状态,所以可以进入if语句,然后呢,我要把这个数字1放在第一位,那么这个数字肯定首先会被使用,所以首先用st[i] = true;这个语句来标记1这个数字已经被使用。然后让第一位上的数字为1,所以有nums[u] = i;这个语句;我第一位上的是数字1以后,我想继续接着给下面的位置赋上数字,把剩下的2和3给放在剩下的两个位置上。所以直接用递归,所以就有dfs(u + 1, nums, st);这个语句。用这个语句不断地调用自己这个函数,不断地为每个位置上赋数字。*/st[i] = false;/*这是回溯的语句,是关键语句,没这个语句是无法正确的得到结果的*/}}}
}int main()
{int nums[N];/*这个数组表示的是每一位上的数字,就是1——n中的某一个数字,根据布尔数组标记的每个数的状态来决定是否取数字,该取哪些数字。*/bool st[N] = {0};/*这个是定义的一个布尔数组,用这个布尔数组来标记每一位上数字是否被使用过,是用来判断数字的使用状态的一个量。 这里刚开始把布尔数组初始化为0,意思是这个时候的数字都没有被使用,都是false状态。*/scanf("%d", &n);//这里是输入数字n,就是题中说的给定整数n。dfs(1, nums, st);/*这里注意哈,我是从第一位开始的,所以我这里第一位写的是1,意思是我从第一位开始执行这个函数。对应着上面的u,u表示的是第几位,假设n=3的话,那么u就依次为1 2 3。*/return 0;
}

这代码中蕴藏的知识十分多,让我一一来解释与总结。

 一、其中的代码语句的深刻理解。

1、st[i] = false;

  该语句会将当前选择的元素标记为未使用,从而恢复现场,回溯到之前的状态。这个过程是在dfs函数中进行的,当搜索到一个合法的方案时,dfs函数会向上回溯,并且撤销之前做出的选择,重新搜索其他的可能性。这样就可以保证每次选择都基于之前的选择和状态,并且不会重复选取相同的元素或进入死循环。

2、dfs(1, nums, st);

  在这段代码中,dfs(1, nums, st);语句的作用是调用dfs函数,开始进行深度优先搜索。

  具体地说,dfs(1, nums, st);表示从第一位开始搜索排列结果。在dfs函数内部,它会遍历数字1到n,并检查每个数字是否已经被使用过。如果一个数字没有被使用过,那么将其标记为已使用,并将其放置在当前位置上(即nums[u] = i;)。然后,递归调用dfs函数,继续向下一位数字进行搜索(即dfs(u + 1, nums, st);)。

通过递归调用的方式,程序会不断地尝试不同的数字组合,直到所有位置都被填满(即u > n)。在这种情况下,会输出当前得到的一种排列结果。

最后,回溯的过程会将之前标记为已使用的数字重新标记为未使用(即st[i] = false;),以便在后续的搜索中可以重新选择这些数字。总体来说,dfs(1, nums, st);语句的作用是启动深度优先搜索算法,找到所有可能的数字排列结果并输出。

 

二、代码中的知识点。

1、回溯。

(1)什么是回溯

  回溯(Backtracking)是一种经典的算法解决方法,用于在问题的解空间中搜索所有可能的解。回溯算法通过穷举搜索的方式,逐步构建候选解,并在搜索过程中进行剪枝,从而避免无效的搜索。

  回溯算法的基本思想是,从问题的起始状态开始,通过一系列的选择和约束条件,逐步构建候选解,每次都进行尝试,并在遇到无效选择时及时回溯,撤销当前选择,继续探索其他可能的选择,直到找到满足所有条件的解或搜索完整个解空间。

  回溯算法通常使用递归来实现,通过递归函数的参数传递状态信息,并通过递归的深入和回溯的返回来实现搜索的过程。在每一层递归中,根据问题的约束条件,进行选择、处理和撤销操作,直到达到终止条件。

  回溯算法适用于求解组合、排列、子集、棋盘类等问题,这些问题通常具有多个选择和约束条件。在搜索过程中,回溯算法通过剪枝和优化策略,可以有效地减少不必要的搜索空间,提高算法的效率。

  需要注意的是,回溯算法的复杂度通常较高,因为它会涉及到大量的搜索和尝试。在实际应用中,可以通过合理设计剪枝条件、优化算法逻辑等方式来提高回溯算法的效率。

(2)回溯的作用是什么。

  回溯的主要作用是在求解问题时,通过穷举搜索的方式找到所有可能的解或最优解。

具体来说,回溯算法的作用包括:

  1. 枚举所有可能的解:回溯算法通过递归调用和回溯的方式,在问题的解空间中穷举所有可能的解。它会尝试每一种可能的选择,并继续向下搜索,直到找到满足问题条件的解或搜索完整个解空间。

  2. 剪枝和优化:在搜索过程中,回溯算法会根据问题的约束条件进行剪枝和优化。当发现当前路径已经无法满足问题的条件时,回溯算法会及时返回上一层,撤销之前的选择,避免继续无效的搜索。这样可以减少不必要的计算和时间复杂度。

  3. 还原状态和回退:回溯算法在搜索过程中会记录选择和状态信息,使得在回溯时能够还原状态和回退到上一层。这样可以保证每次选择都是基于之前的选择和状态,并且不会重复选取相同的元素或进入死循环。

  4. 解决组合、排列、子集等问题:回溯算法特别适用于求解组合、排列、子集等问题,这些问题通常具有多个选择和约束条件。回溯算法可以通过穷举搜索的方式,逐步构建候选解,并在搜索过程中进行剪枝,找到满足问题条件的解。

  总而言之,回溯的作用是通过穷举搜索的方式,寻找所有可能的解或最优解。它通过剪枝和优化策略,减少不必要的搜索,提高算法的效率。回溯算法广泛应用于组合优化、图搜索、布尔满足问题等领域。

2、布尔数组的使用与初始化。

代码中对应的语句:bool st[N] = {0};

  在C++中,可以使用大括号 {} 初始化数组。对于布尔类型的数组,0代表false,非0值代表true。因此,bool st[N] = {0};表示将数组st的所有元素初始化为false

  具体地说,st是一个布尔类型的数组,长度为N。通过{0}进行初始化,会将数组的所有元素都设置为false这样做的目的是确保在开始搜索之前,所有数字都被标记为未使用状态。

  这个语句的作用是创建一个长度为N的布尔数组st,并将所有元素初始化为false,以便在后续的搜索中通过修改数组元素的值来标记数字的使用状态。

这就是所有的总结了,其中递归与回溯涉及的高级算法我还未去涉及,等学习完了以后再回来补充。

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

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

相关文章

【Linux】驱动

驱动 驱动程序过程 系统调用 用户空间 内核空间 添加驱动和调用驱动 驱动程序是如何调用设备硬件 驱动 在计算机领域&#xff0c;驱动&#xff08;Driver&#xff09;是一种软件&#xff0c;它充当硬件设备与操作系统之间的桥梁&#xff0c;允许它们进行通信和协同工作。驱动程…

[已解决】uniapp内置插件,editor富文本报错(附quill.min.js、image-resize.min.js文件)

在使用uni-app运行内置插件editor时&#xff0c;无法输入内容&#xff0c;控制台报错 原因&#xff1a;查看官网得知&#xff0c;需动态引入quill.min.js、image-resize.min.js文件 解决方法&#xff1a; 1.下载quill.min.js、image-resize.min.js到项目static/eidtor文件中 链…

云原生之深入解析Kubernetes Operator的最佳实践和最常见的问题分析

一、Kubernetes Operator 简介 Kubernetes Operator 是通过连接主 API 并 watch 时间的一组进程&#xff0c;一般会 watch 有限的资源类型。当相关 watch 的 event 触发的时候&#xff0c;operator 做出响应并执行具体的动作。这可能仅限于与主 API 交互&#xff0c;但通常会涉…

Linux下FFmepg使用

1.命令行录一段wav,PCM数据 ffmpeg -f alsa -i hw:0,0 xxx.wav//录制 ffplay out.wav//播放ffmpeg -f alsa -i hw:0,0 -ar 16000 -channels 1 -f s16le 1.pcm ffplay -ar 16000 -channels 1 -f s16le 1.pcm -ar freq 设置音频采样率 -ac channels 设置通道 缺省为1 2.将pcm…

Kubernetes实战(十四)-k8s高可用集群扩容master节点

1 单master集群和多master节点集群方案 1.1 单Master集群 k8s 集群是由一组运行 k8s 的节点组成的&#xff0c;节点可以是物理机、虚拟机或者云服务器。k8s 集群中的节点分为两种角色&#xff1a;master 和 node。 master 节点&#xff1a;master 节点负责控制和管理整个集群…

PyTorch官网demo解读——第一个神经网络(1)

神经网络如此神奇&#xff0c;feel the magic 今天分享一下学习PyTorch官网demo的心得&#xff0c;原来实现一个神经网络可以如此简单/简洁/高效&#xff0c;同时也感慨PyTorch如此强大。 这个demo的目的是训练一个识别手写数字的模型&#xff01; 先上源码&#xff1a; fr…

Composer 安装与使用

Composer 是 PHP 的一个依赖管理工具。我们可以在项目中声明所依赖的外部工具库&#xff0c;Composer 会帮你安装这些依赖的库文件&#xff0c;有了它&#xff0c;我们就可以很轻松的使用一个命令将其他人的优秀代码引用到我们的项目中来。 Composer 默认情况下不是全局安装&a…

vue3 element-plus 日期选择器 el-date-picker 汉化

vue3 项目中&#xff0c;element-plus 的日期选择器 el-date-picker 默认是英文版的&#xff0c;如下&#xff1a; 页面引入&#xff1a; //引入汉化语言包 import locale from "element-plus/lib/locale/lang/zh-cn" import { ElDatePicker, ElButton, ElConfigP…

西南科技大学数据库实验二(表数据插入、修改和删除)

一、实验目的 &#xff08;1&#xff09;学会用SQL语句对数据库进行插入、修改和删除数据操作 &#xff08;2&#xff09;掌握insert、update、delete命令实现对表数据插入、修改和删除等更新操作。 二、实验任务 创建数据库&#xff0c;并创建Employees表、Departments表和…

微服务网关Gateway

springcloud官方提供的网关组件spring-cloud-starter-gateway,看pom.xml文件,引入了webflux做响应式编程,请求转发用到了netty的reactor模型,支持的请求数在1W~1.5W左右。hystrix停止维护后,官方推荐resilience4j做服务熔断,网关这里也能看到依赖。 对于网关提供的功能…

Unity 使用AddTorque方法给刚体施加力矩详解

给刚体施加力&#xff0c;除了使用AddForce方法&#xff0c;我们还可以使用AddTorque方法。该方法是通过施加力矩给刚体以力。AddTorque方法从形式上跟AddForce差不多&#xff0c;它也有4个重载方法&#xff1a; 1、AddTorque(Vector3 torque)&#xff1b;使用Vector3类型参数…

在Node.js中MongoDB查询分页的方法

本文主要介绍在Node.js中MongoDB查询分页的方法。 目录 Node.js中MongoDB查询分页使用原生的mongodb驱动程序查询分页使用Mongoose库进行查询分页注意项 Node.js中MongoDB查询分页 在Node.js中使用MongoDB进行查询分页&#xff0c;可以使用原生的mongodb驱动程序或者Mongoose库…

【web安全】密码爆破讲解,以及burp的爆破功能使用方法

前言 菜某总结&#xff0c;欢迎指正错误进行补充 密码暴力破解原理 暴力破解实际就是疯狂的输入密码进行尝试登录&#xff0c;针对有的人喜欢用一些个人信息当做密码&#xff0c;有的人喜欢用一些很简单的低强度密码&#xff0c;我们就可以针对性的生成一个字典&#xff0c;…

【Linux】文件系统、文件系统结构、虚拟文件系统

一、文件系统概述 1. 什么是文件系统&#xff1f;2. 文件系统&#xff08;文件管理系统的方法&#xff09;的种类有哪些&#xff1f;3. 什么是分区&#xff1f;4. 什么是文件系统目录结构&#xff1f;5. 什么虚拟文件系统Virtual File System &#xff1f;6. 虚拟文件系统有什…

OpenAI开源超级对齐方法:用GPT-2,监督、微调GPT-4

12月15日&#xff0c;OpenAI在官网公布了最新研究论文和开源项目——如何用小模型监督大模型&#xff0c;实现更好的新型对齐方法。 目前&#xff0c;大模型的主流对齐方法是RLHF&#xff08;人类反馈强化学习&#xff09;。但随着大模型朝着多模态、AGI发展&#xff0c;神经元…

Spring Boot SOAP Web 服务端和客户端

一. 服务端 1. 技术栈 JDK 1.8&#xff0c;Eclipse&#xff0c;Maven – 开发环境SpringBoot – 基础应用程序框架wsdl4j – 为我们的服务发布 WSDLSOAP-UI – 用于测试我们的服务JAXB maven 插件 – 用于代码生成 2.创建 Spring Boot 项目 添加 Wsdl4j 依赖关系 编辑pom…

cesium 自定义贴图,shadertoy移植教程。

1.前言 cesium中提供了一些高级的api&#xff0c;可以自己写一些shader来制作炫酷的效果。 ShaderToy 是一个可以在线编写、测试和分享图形渲染着色器的网站。它提供了一个图形化的编辑器&#xff0c;可以让用户编写基于 WebGL 的 GLSL 着色器代码&#xff0c;并实时预览渲染结…

006 Windows共享

一、共享要求 一般是局域网内使用 1、物理上处于统一局域网 同一公司的网络同一家庭的网络连接同一手机热点的主机 2、逻辑上处于同一局域网 直接可以ping对方主机&#xff08;能够直接访问到&#xff09; 二、共享权限 1、共享权限 一般设置为everyone完全控制 2、NTF…

基于3D-CGAN的跨模态MR脑肿瘤分割图像合成

3D CGAN BASED CROSS-MODALITY MR IMAGE SYNTHESIS FOR BRAIN TUMOR SEGMENTATION 基于3D-CGAN的跨模态MR脑肿瘤分割图像合成背景贡献实验方法Subject-specific local adaptive fusion&#xff08;针对特定主题的局部自适应融合&#xff09;Brain tumor segmentation model 损失…

K8s投射数据卷

目录 一.Secret 1.secret介绍 2.secret的类型 3.创建secret 4.使用secret 环境变量的形式 volume数据卷挂载 二ConfigMap 1.创建ConfigMap的方式 2.使用ConfigMap 2.1作为volume挂载使用 2.2.作为环境变量 三.Downward API 1.以环境变量的方式实现 2.Volume挂载 一.S…