【问题描述】输入整数N( 1 <= N <= 10 ),生成从1~N所有整数的全排列。
【输入形式】输入整数N。
【输出形式】输出有N!行,每行都是从1~N所有整数的一个全排列,各整数之间以空格分隔。各行上的全排列不重复。输出各行遵循"小数优先"原则, 在各全排列中,较小的数尽量靠前输出。如果将每行上的输出看成一个数字,则所有输出构成升序数列。具体格式见输出样例。
【样例输入1】1
【样例输出1】1
【样例说明1】输入整数N=1,其全排列只有一种。
【样例输入2】3
【样例输出2】 各输出按字典排序
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
可以用回溯算法来解决,排列属于回溯算法解决的范畴
回溯算法?即回溯搜索法。
1.一种搜索方式。回溯是递归的副产品,只要有递归就会有回溯。
2.回溯法并不高效。因为回溯的本质是穷举,穷举所有可能,然后选出我们想要的答案,如果想让回溯法高效一些,可以加一些剪枝的操作,但也改变不了回溯法就是穷举的本质。既然回溯算法效率这么底下,为什么还要用回溯算法呢?这是因为我们在求解问题当中,一些问题用暴力求解就不错了,很难用高效的算法求出。
3.如何理解?
回溯算法解决的问题都可以抽象为树形结构。因为回溯法解决的都是在集合中递归查找子集,集合的大小就构成了树的宽度,递归的深度就构成的树的深度。递归就要有终止条件,所以必然是一棵高度有限的树(N叉树)。
下面的图可以很好的描述了
本题的树形结构
可以看出叶子节点,就是我们要的结果
那么什么时候,算是到达叶子节点呢?
当收集元素的数组path的大小达到和nums数组一样大的时候,说明找到了一个全排列,也表示到达了叶子节点。
#include<iostream>
#include<algorithm>
using namespace std;
const int N=10;
bool used[N];//用来判断1-n个数是否已经被选。true表示已经被选,false反之
int path[N];//用来记录1-n个位置选的是哪个数
int n;
void dfs(int m)
{
if(m>n){//当n个位置确定之后开始打印结果
for(int i=1;i<=n;i++){
cout<<path[i]<<" ";
}
cout<<endl;
return;
}
for(int i=1;i<=n;i++){
if(!used[i])//如果这个数没有被选
{
used[i]=true;//选择这个数并打上标记
path[m]=i;//记录
dfs(m+1);//开始枚举下一个位置
used[i]=false;//恢复现场
}
}
}
int main()
{
cin>>n;
dfs(1);//从第一个位置开始遍历
return 0;
}
还有其他的方法,用python的内置函数itertools.permutations,会更简便一些。
itertools.permutations(a, b) 连续返回由a元素[生成的长度为b的全排列组合
s=[1,2,3]
itertools.permutations(s,3)
# permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC
# permutations(range(3)) --> 012 021 102 120 201 210
如果考试写程序建议用python
import itertools
n = int(input())
s = []
for i in range(1, n + 1):
s.append(i)
num = list(itertools.permutations(s, n))
for ch in num:
for c in ch:
print(c,end='')
print()
函数用法,再如如下示例
import itertools
sum = 0
a=[1, 2, 3, 4, 5]
for i in itertools.permutations(a,2):
print(i)
sum += 1
print(sum)
b = list(itertools.permutations(a, 2))
print(b)
print(len(b))
输出
(1, 2)
(1, 3)
(1, 4)
(1, 5)
(2, 1)
(2, 3)
(2, 4)
(2, 5)
(3, 1)
(3, 2)
(3, 4)
(3, 5)
(4, 1)
(4, 2)
(4, 3)
(4, 5)
(5, 1)
(5, 2)
(5, 3)
(5, 4)
20
[(1, 2), (1, 3), (1, 4), (1, 5), (2, 1), (2, 3), (2, 4), (2, 5), (3, 1), (3, 2), (3, 4), (3, 5), (4, 1), (4, 2), (4, 3), (4, 5), (5, 1), (5, 2), (5, 3), (5, 4)]
20