1.生成1-n的排列
递归生成,每一次递归选出当前位置的数,若之前选过则不再选
代码:

#include <iostream> #include <cstdio> using namespace std; void print_permutation(int *A, int n, int cur) { if(cur == n) { for(int i = 0; i < n; i++) printf("%d%c", A[i], (i == n - 1 ? ' ' : ' ')); return; } for(int i = 1; i <= n; i++) { int ok = 1; for(int j = 0; j < cur; j++) if(A[j] == i) ok = 0; if(ok) { A[cur] = i; print_permutation(A, n, cur + 1); } } } int main() { int n; int *A; while(cin >> n) { A = new int[n]; print_permutation(A, n, 0); } return 0; }
2.给定一个数组P,输出P元素的全排列
递归生成,类似于1-n排列,每一次递归查找之前的数是否出现,但由于数组内可能会有重复的数字,所以是否出现的检测办法是查看当前数组与原始数组中该数字出现的次数是否相同,还有一个比较难理解的大坑,,输入1, 1, 1,会输出27个1 1 1;原因是在选择数字的时候,哪怕这个数字已经出现在已得到的数组中,他也可能被选中。比如:数组{1(0), 1(1), 1(2)}, 括号里的是下标,第一次递归选择的是1(0), 到第二个递归,由于是从i= 0开始查找,那么第二次递归也可能选择1(0), 到最后就可能出现{1(0), 1(0), 1(0)}这种数列的存在,于是就会打出27次答案,就算i不同不选取,事实上{1(0),1(1),1(2)}与{1(2),1(1),1(0)}实际上也是属于一种,那么实现的方法就是,现将数组P排序,那么相同数字就会出现在相邻的位置,在每次选择的时候每种数字只需要考虑一次就够了,如果P[i] == P[i-1],就直接跳过不考虑就好了(i != 0),
实现代码:

1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 void print_permutation(int *A, int *P, int n, int cur) 5 { 6 if(cur == n) 7 { 8 for(int i = 0; i < n; i++) 9 printf("%d%c", A[i], (i == n - 1 ? ' ' : ' ')); 10 return; 11 } 12 for(int i = 0; i < n; i++) 13 { 14 if(!i || P[i] != P[i-1]) 15 { 16 int r1 = 0, r2 = 0; 17 for(int j = 0; j < n; j++) 18 if(P[j] == P[i]) r1++; 19 for(int j = 0; j < cur; j++) 20 if(A[j] == P[i]) r2++; 21 if(r1 > r2) 22 { 23 A[cur] = P[i]; 24 print_permutation(A, P, n, cur + 1); 25 } 26 } 27 28 } 29 } 30 int main() 31 { 32 int n; 33 int *A; 34 int *P; 35 while(cin >> n) 36 { 37 A = new int[n]; 38 P = new int[n]; 39 for(int i = 0; i < n; i++) 40 cin >> P[i]; 41 print_permutation(A, P, n, 0); 42 } 43 return 0; 44 }
3.next_permutation
c++<algorithm>里的一个函数,把当前数组改成此数组的下一个字典序排列,如果当前数组不存在下一个排列,则返回false。比如A[] = {1,3,5,4,2}的下一个排列是{1,4,2,3,5},根据该函数的实现原理 ,我自己写了一个函数(功能没有库函数里那么强大,不过比较简单的还是能应付的,主要给自己理解用 )

1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 void swap(int &a, int &b) 5 { 6 int c = a; 7 a = b; 8 b = c; 9 } 10 11 bool next_permutation(int *A, int n) 12 { 13 if(n == 1)return false; 14 int i = n - 2; 15 int j = n - 1; 16 while(i >= 0 && A[i] >= A[i+1])i--; 17 if(i == -1)return false; 18 while(A[i] >= A[j])j--; 19 swap(A[i], A[j]); 20 int k1 = i + 1; 21 int k2 = n - 1; 22 for(; k1 < k1 + (k2 - k1) / 2; k1++, k2--) 23 swap(A[k1], A[k2]); 24 return true; 25 } 26 int main() 27 { 28 int n; 29 while(cin >> n) 30 { 31 int *A = new int[n]; 32 for(int i = 0; i < n; i++) 33 cin >> A[i]; 34 do 35 { 36 for(int i = 0; i < n; i++) 37 printf("%d%c", A[i], (i == n-1 ? ' ' : ' ')); 38 }while(next_permutation(A, n)); 39 } 40 return 0; 41 }