文章目录
- 原题链接
- 题目描述
- 输入格式
- 输出格式
- 数据范围
- 输入样例:
- 输出样例:
- 题目分析
- 示例代码
原题链接
94. 递归实现排列型枚举
题目难度:简单
题目描述
把 1 ∼ n 1 \sim n 1∼n 这 n n n 个整数排成一行后随机打乱顺序,输出所有可能的次序。
输入格式
一个整数 n n n。
输出格式
按照从小到大的顺序输出所有方案,每行 1 1 1 个。
首先,同一行相邻两个数用一个空格隔开。
其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面。
数据范围
1 ≤ n ≤ 9 1 \le n \le 9 1≤n≤9
输入样例:
3
输出样例:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
题目分析
这道题的意思很简单,就是生成从 1 ∼ n 1 \sim n 1∼n的全排列,第二个要求就是要按照字典序从小到大输出,字典序就是对于两个序列或者字符串,从头开始比较,只要相同就向后移动,不同的话就是谁小谁的字典序就小,如果都相同就是字典序相同,规定短的序列字典序较小
我们看到数据范围是到 9 9 9的,因此我们可以大致判断出这个题的时间复杂度限制在 O ( n ∗ n ! ) O(n*n!) O(n∗n!)即可
我们在枚举全排列时有两种方式
第一种是依次枚举每个数放到不同的位置,即固定选择一个数,按照不同位置分类
第二种是依次枚举每个位置放不同的数,即固定选择一个位置,按照不同的数分类
对于本质上的算法其实是一样的,对于具体理解其实是不太相同的
为了便于画图,我们采取第二种方式,画出递归搜素树
我们就可以通过这样一个过程,依次枚举每个位置,将不同的数字放入其中,直到我们枚举到最后一个位置,将答案输出即可
我们也需要记录每个位置的状态,可以采用数组或者数位来记录,这里我们同样采用数组的方式,除此之外,我们需要记录哪些数字被用过,因此我们需要一个布尔数组来记录
示例代码
#include<iostream>
using namespace std;
const int N = 10; // 数据范围,为了方便理解,我们直接取从1到n,因此需要开十个空间
int n;
int state[N]; // 记录状态的数组,每个位置上填入已经选中的数字
bool used[N]; // 记录是否被使用过,未被使用则为false,使用过则为true
void dfs(int cur) // cur表示当前枚举到第cur位
{
// 首先判断何时递归完成
if (cur > n)// 这里表示我们已经把最后一个位置的数据枚举完成了
{
for (int i = 1; i <= n; i++) // 输出结果
cout << state[i] << ' ';
cout << '\n';
return;
}
// 枚举每个数字,填入state数组
for (int i = 1; i <= n; i++)
{
if (used[i] == false) // 如果未被使用
{
state[cur] = i; // 填入数字i
used[i] = true; // 表示该数字被使用过了
dfs(cur + 1); // 递归到下一个位置进行处理
// 恢复未使用时的状态
state[cur] = 0;
used[i] = false;
}
}
}
int main()
{
cin >> n;
dfs(1); // 表示从第一个位置开始枚举
return 0;
}
感谢各位的支持,如果你发现文章中有任何不严谨或者需要补充的部分,欢迎在评论区指出