生成1~n的排列
#include <iostream>
using namespace std;
void print_permutation(int n, int A[], int cur){
if(cur == n){
for(int i=0; i<n; i++)
printf("%d ",A[i]);
printf("\n");
}
else for(int i=1; i<=n; i++){
bool ok = true;
for(int j=0; j<cur; j++)
if(A[j] == i)
ok = false;
if(ok){
A[cur] = i;
print_permutation(n, A, cur+1);
}
}
}
int main(int argc, const char * argv[]) {
int A[9];
print_permutation(9, A, 0);
return 0;
}
生成可重集的排列
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <cstdio>
#include <algorithm>
using namespace std;
vector<int> P;
void scan(){
string numbers;
getline(cin,numbers);
stringstream ss(numbers);
char number;
// 遇到空格则视为下一个循环
while(ss >> number) P.push_back(number - '0');
}
void print_permutation(vector<int> &P, int A[], int cur){
if(cur==P.size()){
for(int i=0;i<cur;i++)
printf("%d",A[i]);
printf("\n");
}
else for(int i=0;i<P.size();i++)
// 因为要求不输出重复排列,那么对于重复数字来说,
// 我们得视为1个,也就是说,每次循环只能出现这些数中的一个
// 这样,无论再多也是1x1x1...
if(!i||P[i]!=P[i-1]){
int cnt1=0,cnt2=0;
// 我们还要保证重复数字出现的数目不能超过其有的数目
for(int j=0;j<cur;j++) if(A[j]==P[i]) cnt1++;
for(int j=0;j<P.size();j++) if(P[j]==P[i]) cnt2++;
if(cnt1<cnt2){
A[cur] = P[i];
print_permutation(P, A, cur+1);
}
}
}
int main(int argc, const char * argv[]) {
scan();
// 在开始前,务必要排序
sort(P.begin(),P.end());
const vector<int>::size_type n = P.size();
int A[n];
print_permutation(P, A, 0);
return 0;
}
下一个排列
介绍
bool next_permutation(iterator start, iterator end);
// 输出所有比当前排序大的排列,顺序是从小打大;
// prev_permutation则是相反。
代码
#include <iostream>
#include <algorithm>
using namespace std;
int main(int argc, const char * argv[]) {
int n,p[10];
scanf("%d",&n);
for(int i=0; i<n; i++) scanf("%d", &p[i]);
sort(p,p+n);
do{
for(int i=0; i<n; i++) printf("%d",p[i]);
printf("\n");
}while(next_permutation(p, p+n));
return 0;
}
可以看到,它只生成比当前排列大的一个排列。如果这个排列到头了,返回false。
总结
综上所述,实现枚举排列的方法有两种:
- 递归法;
- next_permutation.