枚举排列

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;
}
View Code

 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 }
View Code

 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 }
View Code
print “ 欢迎来到渣小狼的博客,这既是博客,也是日记,里面记录了小狼的学习经历还有一些小狼的见解,非常希望每一个来到这里的人能够留下只言片语,更加的希望留下的是对于小狼的不足的补充,谢谢(*^__^*) 嘻嘻……”
原文地址:https://www.cnblogs.com/wolf-yasen/p/6592693.html