想不想打印所有排列?
输入整数n,按字典序从小到大输出前n个数的所有排列。
1 生成1~n的排列
伪代码:
void print_permutation(序列A,集合S) { if(S为空) 输出序列A; else按照从小到大的顺序依次考虑S中的每个元素 { print_permutation(在A的末尾添加v后得到的新序列,S-{v}); } }
下面考虑程序实现。用数组A表示序列A,集合S 不用保存,因为它可以有序列A 完全确定-A中没有出现的元素都可以选。
代码:
1 void print_permutation(int n,int*A,int cur) 2 { 3 if(cur==n)//递归边界 4 { 5 for(int i = 0;i<n;i++) 6 { 7 cout << A[i] << " "; 8 } 9 cout << endl; 10 } 11 else 12 { 13 for(int i = 1;i<=n;i++)//尝试在A中填入各种整数i 14 { 15 int ok = 1; 16 for(int j = 0;j<cur;j++) 17 { 18 if(A[j]==i)//如果i已经在A[0]~A[cur-1]出现过,则不能再选 19 { 20 ok = 0; 21 } 22 } 23 if(ok) 24 { 25 A[cur++] = i; 26 print_permutation(n,A,cur);//递归调用 27 cur--; 28 } 29 } 30 } 31 32 }
循环变量i是当前考察的A[cur],上面的程序用到了一个标志变量ok,来看i有没有在A中出现过,ok为1说明没有出现就可以把i加到A[cur]处
声明一个足够大的数组A,然后调用print_permutation(n,A,0);
2 生成可重集的序列
把问题改成输入数组P,并按字典序输出数组A各元素的所有全排列,则需要修改if(A[j]==i)为if(A[j]==P[i]),把A[cur]=i,改成A[cur]=P[i]。
但是如果P中有重复元素就会失效,因为上面的算法是看有无重合元素来判断P[i]在A[j]中出现过没有,来决定是不是添加P[i];
可以统计A[0]~A[cur-1]中P[i]出现的次数c1,和P[i]在P数组中出现的次数c2,只要c1<c2,就能递归调用。
代码:
void print_permutation_2(int n,int*P,int*A,int cur) { if(cur==n) { for(int i = 0;i<n;i++) { cout << A[i] << " "; } cout << endl; } else { for(int i = 0;i<n;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++; for(int j = 0; j<n; j++) if(P[i]==P[j]) c2++; int ok = 1; if(c1<c2) { A[cur++] = P[i]; print_permutation_2(n,P,A,cur); cur--; } } } } }
3 解答树
递归函数的调用可用解答树来表示,
第0层有n个孩子,第一层n-1个孩子,第二层n-2个孩子,...,第n层为叶节点没有孩子,每个叶子对应于一个排列,共n!个叶子。
如果某些问题的解可由多个步骤得到,而每个步骤都有若干种选择,可用递归算法实现,他的工作方式可由解答树描述。
一个重要结论:在多数情况下,解答树上的节点几乎全部来自于最后一两层。和他们相比,上面的节点数可以忽略不计。
4 下一个排列
代码:
1 void print_permutation_3(int n,int* P) 2 { 3 sort(P,P+n); 4 do{ 5 for(int i = 0;i<n;i++) 6 { 7 cout << P[i] << " "; 8 } 9 cout << endl; 10 }while(next_permutation(P,P+n)); 11 }
代码汇总:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <iostream> 2 #include <algorithm> 3 #define max_n 10005 4 using namespace std; 5 int A[max_n]; 6 int P[max_n]; 7 /*void print_permutation(序列A,集合S) 8 { 9 if(S为空) 输出序列A; 10 else按照从小到大的顺序依次考虑S中的每个元素 11 { 12 print_permutation(在A的末尾添加v后得到的新序列,S-{v}); 13 } 14 }*/ 15 void print_permutation(int n,int*A,int cur) 16 { 17 if(cur==n)//递归边界 18 { 19 for(int i = 0;i<n;i++) 20 { 21 cout << A[i] << " "; 22 } 23 cout << endl; 24 } 25 else 26 { 27 for(int i = 1;i<=n;i++)//尝试在A中填入各种整数i 28 { 29 int ok = 1; 30 for(int j = 0;j<cur;j++) 31 { 32 if(A[j]==i)//如果i已经在A[0]~A[cur-1]出现过,则不能再选 33 { 34 ok = 0; 35 } 36 } 37 if(ok) 38 { 39 A[cur++] = i; 40 print_permutation(n,A,cur);//递归调用 41 cur--; 42 } 43 } 44 } 45 46 } 47 void print_permutation_2(int n,int*P,int*A,int cur) 48 { 49 if(cur==n) 50 { 51 for(int i = 0;i<n;i++) 52 { 53 cout << A[i] << " "; 54 } 55 cout << endl; 56 } 57 else 58 { 59 for(int i = 0;i<n;i++) 60 { 61 if(!i||P[i]!=P[i-1]) 62 { 63 int c1 = 0,c2 = 0; 64 for(int j = 0; j<cur; j++) 65 if(A[j]==P[i]) 66 c1++; 67 for(int j = 0; j<n; j++) 68 if(P[i]==P[j]) 69 c2++; 70 int ok = 1; 71 if(c1<c2) 72 { 73 A[cur++] = P[i]; 74 print_permutation_2(n,P,A,cur); 75 cur--; 76 } 77 } 78 } 79 } 80 81 } 82 void print_permutation_3(int n,int* P) 83 { 84 sort(P,P+n); 85 do{ 86 for(int i = 0;i<n;i++) 87 { 88 cout << P[i] << " "; 89 } 90 cout << endl; 91 }while(next_permutation(P,P+n)); 92 } 93 int main() 94 { 95 int P[]={1,2,4,3}; 96 //sort(P,P+4); 97 //print_permutation_2(4,P,A,0); 98 print_permutation_3(4,P); 99 return 0; 100 }