问题要求:输入数组P,并按字典序输出数组A个元素的全排列。
问题来源:刘汝佳大白皮P185
Code:
/*
* Note:
* 序列A 一次全排列
* 序列P 需要进行全排列的数组
* 分析:1~n的全排列easy,用递归实现,这个也是相同的方法,但是在处理出现重复数字的时候会出现问题
* 例如 in:1 1 1 , out:sum=27,这很明显是错的,为什么错,因为每个1都当成与其他1不想同的数来处理了,如
* 何解决这个问题?首先统计出现在数组A中出现的1的次数是否和数组P中的1的数目相同,如果不同则继续递归。
* 这样解决了对3个1都进行排序的问题,但是还没有解决"重复"的问题,i代表数组P的下标,如果数组P中前后两个
* 元素是相同的,那自需要进行一次操作。但是如果输入的是 1 2 1,结果还是出错,为什么?因为数组P是个
* 无序的数组,所以先对其进行一下排序就能完成所要求的操作了。
*/
#include<algorithm>
#include<cstdio>
using namespace std;
int sum;
void print_permutation(int n,int* A,int cur,int* P){ //cur相当于step
if(cur==n){ //递归边界
for(int i=0;i<n;i++) printf("%d ",A[i]);
printf("\n");
sum++;
return;
}
for(int i=0;i<n;i++){ //尝试在A[cur]中填各种整数P[i]
if(!i||P[i]!=P[i-1]){
int c1=0,c2=0;
for(int j=0;j<cur;j++) if(A[j]==P[i]) c1++; //c1是A[0]~A[cur-1]中P[i]出现的次数c1
for(int j=0;j<n;j++) if(P[j]==P[i]) c2++; //c2是P数组中P[i]出现的次数
if(c1<c2){
A[cur]=P[i];
print_permutation(n,A,cur+1,P); //向下递归
}
}
}
}
int main(){
int A[1000],n,P[1000];
while(scanf("%d",&n)!=EOF){
sum=0;
for(int i=0;i<n;i++)
scanf("%d",&P[i]);
sort(P,P+n);
print_permutation(n,A,0,P);
printf("sum = %d\n",sum);
}
return 0;
}