全排列问题
题目描述
按照字典序输出自然数 1 到 n 所有不重复的排列,即 n 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。
输入格式
一个整数 n。
输出格式
由 1 - n 组成的所有不重复的数字序列,每行一个序列。
每个数字保留 5 个场宽。
样例 1
样例输入 1
3
样例输出 1
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
情况一:输出全排列,并且全排列要按照字典序输出
C++的STL库中的头文件<algorithm>中有函数next_permutation()专门用来求全排列。
next_permutation(int *number,int *number+n);参数int *number和int *number+n是指需要排列的数字的区间的左端点和右端点,并且在这个区间内数组元素必须保持从小到大。
一般需要在输出全排列之前将数组元素进行排序(使用sort()函数)。
#include<iostream>
#include<algorithm>
#include<iomanip>
using namespace std;
int main()
{
int n;
cin>>n;
int number[n+1];
for(int i=1;i<=n;i++)
number[i]=i;
do
{
for(int i=1;i<=n;i++)
cout<<setw(5)<<number[i];
cout<<endl;
}while(next_permutation(number+1,number+n+1));
return 0;
}
情况二:统计一个数组内的元素的全排列的个数
方法一:
借用上面的代码,只需要将do-while()循环内的循环输出语句改为计数即可。
int ans=0;
do
{
ans++;
}while(next_permutation(number+1,number+n+1));
cout<<ans<<endl;
方法二:
递归函数模拟全排列的交换过程。将n个数的全排列问题转化为n-1个数的全排列问题,最后不断将问题分解为子问题,最后输出结果。
#include<iostream>
#include<iomanip>
#include<bits/stdc++.h>
using namespace std;
int ans=0;
void Perm(int *number,int left,int right)
{
if(left==right)
{
ans++;
return;
}
else
{
for(int i=left;i<=right;i++)
{
swap(number[left],number[i]);
Perm(number,left+1,right);
swap(number[left],number[i]);
}
}
}
int main()
{
int n;
cin>>n;
int number[n+1];
for(int i=1;i<=n;i++)
number[i]=i;
Perm(number,1,n);
cout<<ans<<endl;
return 0;
}
同样,上面的代码也可以输出全排列,但是无法确保输出的数据的有序性。只需要将left==right的情况下用来计数的代码替换成输出的代码即可。
代码如下:
#include<iostream>
#include<iomanip>
#include<bits/stdc++.h>
using namespace std;
void Perm(int *number,int left,int right)
{
if(left==right)
{
for(int i=1;i<=right;i++)
cout<<setw(6)<<number[i];
cout<<endl;
}
else
{
for(int i=left;i<=right;i++)
{
swap(number[left],number[i]);
Perm(number,left+1,right);
swap(number[left],number[i]);
}
}
}
int main()
{
int n;
cin>>n;
int number[n+1];
for(int i=1;i<=n;i++)
number[i]=i;
Perm(number,1,n);
return 0;
}