题目描述:
把 1∼n 这 n 个整数排成一行后随机打乱顺序,输出所有可能的次序。
输入格式:
一个整数 n。
输出格式:
按照从小到大的顺序输出所有方案,每行 1 个。
首先,同一行相邻两个数用一个空格隔开。
其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面。
数据范围:
1≤n≤9
输入样例:
3
输出样例:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
分析步骤:
第一:理清思路:
-
我们这道题还是DFS去求解,但是这道题目要我们求解的是排列型枚举,所以和组合型不一样。大家要明白组合和排列的区别。我们求解DFS有两种方法,一种是枚举位置;一种是枚举数字。本题采用枚举位置的方法,因为这个更简单跟容易理解。
-
枚举位置,我们先枚举第一个位置他有三种选择1,2,3这样我们就可以像一颗树一样去画出来,在第一个位置上选择1的情况下还有两个位置,所以我们可以分别选择2,3,再分别选择1,2;1,3的情况下再选择那个没有选择过的。就形成123,132的情况。之后的情况大家可以动手画画。
第二:书写主函数,构建整体框架:
-
输入值,进入DFS这个1代表我们已经遍历到了第几个位置。书写DFS我们一定要明白,自己对于变量的定义是什么,只有明白了我们在之后的递归中才不会迷失。
int main()
{
cin>>n;
dfs(1);
return 0;
}
第三:书写DFS函数:
-
我们一般写DFS先确定结束的条件。我们这道题因为是枚举位置,所以我们x>n的时候就代表着我们合理的位置都已经有了数字,不能等于n,因为当x==n时我们正要选择最后一个位置的数,还没完,最终所以我们就按照之前存储的顺序输出出来就可以。
-
如果x<=n的时候就代表还没结束,我们就用for循环去遍历,看看哪个数还没有被选择过,没有被选择过的话就将这个数选择进入数组,更改一下状态,再进入下一次的递归搜索,搜索完之后就得返回恢复现场。像这道题目就一定得恢复现场,因为如果不恢复现场那么123被选择过之后状态就只会是true,之后就不能排序列出其他的顺序了。
void dfs(int x){
if(x > n){
for(int i = 1; i <= n ; i ++){
cout<<path[i]<<" ";
}
cout<<endl;
}
else{
for(int i = 1 ; i <= n ; i ++){
if(!st[i]){
st[i] = true;
path[x] = i;
dfs(x+1);
st[i] = false;
path[x] = 0;
}
}
}
}
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 20;
int n ;
int path[N];
bool st[N];
void dfs(int x){
if(x > n ){
for(int i = 1; i <= n ; i ++){
cout<<path[i]<<" ";
}
cout<<endl;
}
else{
for(int i = 1 ; i <= n ; i ++){
if(!st[i]){
st[i] = true;
path[x] = i;
dfs(x+1);
st[i] = false;
path[x] = 0;
}
}
}
}
int main()
{
cin>>n;
dfs(1);
return 0;
}