全排列算法(递归)

一、题目描述

输入一个数n,请你写出1~n的全排列。

全排列定义:从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。

例如:

输入

3

输出

123
132
213
231
312
321

二、算法分析

对于这类题,我们很直接了当的就知道可以用暴力枚举去完成算法,具体做法就是从1~3中任选一个数放在第一位,之后再从剩余的两个里面任选一个放在第二位,最后一个放在最后一位。不过,今天我们要介绍一个更“高级”的算法——递归算法。

递归算法主要有三个组成部分:初始化、循环体(递归函数)、递归终止条件

初始化:即将递归所需要的已经明确的数据储存在需要的、合适的容器中,并申请一些辅助变量配合进行递归算法的实现;

循环体:也叫递归函数,是递归算法的主体,它的作用就是不断调用自己,通过取不同的值来达到我们所需要的结果;

递归终止条件:是递归算法的重中之重,它是结束递归算法的基石,如果没有它,算法会一直进行下去。

比如上面的算法,它的循环体就是对1~3进行连续存取,通过存取的顺序来对数据排序。但是,有一个问题,就是我该如何判定这个数用没用过,为了判断这个数,我们需要用一个tof数组(ture or false)来进行标记,也就是初始化一个tof数组,同时,我还需要初始化另一个数组ans[]来存储已经标记好的数。那么递归结束的条件是什么呢,就是这个ans[]的长度为3,此时我们就要输出ans。要特别注意的是,每当我们递归调用完一次后,需要将我们已经变动过的数据复原,以便进行下一次循环。

三、代码

#include <bits/stdc++.h>
using namespace std;
int tof[10];
int ans[10];
int n;
void dp(int num) {
	if (num > n) {    //终止条件就是ans长度大于三,因为我们是从1开始进行的,如果从0开始进行,则需                        
                        要加一个等于
		for(int i=1;i<=n;i++){    //注意,下标要从1开始
           i==1?(cout<<ans[i]):(cout<<' '<<ans[i]);  //多目运算,格式规范化
        cout<<endl;
		return;
	}
	for (int i = 1; i <= n; i++) {  //从1到n选择一个数进行排列
		if (!tof[i]) {       //判断这个数是否被选过,选过则跳过,没有则存储下来并且标记为1
			tof[i] = 1;      //标记为已选
			ans[num] = i;    //存储下来
			dp(num+1);       //存储后,数组长度加一,然后继续选择
			tof[i] = 0;      //递归结束,数据复原
		}
	}
}

int main() {
    cin>>n;
	dp(1);   //ans数组长度从1开始增加
	return 0;
}

同时,这个答案也是类似题目的一种模板,请看下面一题:

洛谷P1008 [NOIP1998 普及组] 三连击

题目背景

本题为提交答案题,您可以写程序或手算在本机上算出答案后,直接提交答案文本,也可提交答案生成程序。

题目描述

将 1,2,…,9共 9个数分成 3 组,分别组成 3 个三位数,且使这 3 个三位数构成 1:2:3的比例,试求出所有满足条件的 3 个三位数。

输入格式

输出格式

若干行,每行 3 个数字。按照每行第 1 个数字升序排列。

输入输出样例

输入 #1复制

输出 #1复制

192 384 576
* * *
...

* * *
(剩余部分不予展示)

根据上述知识,我们可以很快写出代码

#include <bits/stdc++.h>

using namespace std;
int tof[10];
int sumnum[10];

void dp(int num) {

	if (num > 9) {
		//全排列完成后进行数据的计算
		int a = sumnum[1] * 100 + sumnum[2] * 10 + sumnum[3];
		int b = sumnum[4] * 100 + sumnum[5] * 10 + sumnum[6];
		int c = sumnum[7] * 100 + sumnum[8] * 10 + sumnum[9];
		if (a * 2 == b && a * 3 == c) {       //终止条件
			cout << a << ' ' << b << ' ' << c << endl;
			return;
		}
	}
	for (int i = 1; i <= 9; i++) {
		if (!tof[i] ) {
			tof[i] = 1;
			sumnum[num] = i;
			dp(num+1);
			tof[i] = 0;
		}
	}
}

int main() {
	dp(1);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值