求全排列和组合问题

时间:2022-02-12 03:39:12

 

1.排列:全排列n!
  使用next_permutation函数

 1 输出序列{1,2,3,4}字典序的全排列。
 2 #include <iostream>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 int main(int argc, char** argv) {
 7 int a[4]={1,2,3,4};
 8 sort(a,a+4);
 9 do{
10 //cout<<a[0]<<" "<<a[1]<<" "<<a[2]<<" "<<a[3]<<endl;
11 for(int i=0;i<4;i++)
12 cout<<a[i]<<" ";
13 cout<<endl;
14 }while(next_permutation(a,a+4));
15 return 0;
16 }

输入任意一个字符串,输出其字典序的全排列

 1 #include <iostream>
 2 #include<algorithm>
 3 using namespace std;
 4 
 5 int main(int argc, char** argv) {
 6 string str;
 7 cin>>str;
 8 sort(str.begin(),str.end());
 9 do{
10 cout<<str<<endl;
11 }while(next_permutation(str.begin(),str.end()));
12 return 0;
13 }

递归法

设一组数p = {r1, r2, r3, … ,rn}, 全排列为perm(p),pn = p – {rn}。则perm(p) = r1perm(p1), r2perm(p2), r3perm(p3), … , rnperm(pn)。当n = 1时perm(p} = r1。
如:求{1, 2, 3, 4, 5}的全排列
1、首先看最后两个数4, 5。 它们的全排列为4 5和5 4, 即以4开头的5的全排列和以5开头的4的全排列。
由于一个数的全排列就是其本身,从而得到以上结果。
2、再看后三个数3, 4, 5。它们的全排列为3 4 5、3 5 4、 4 3 5、 4 5 3、 5 3 4、 5 4 3 六组数。
即以3开头的和4,5的全排列的组合、以4开头的和3,5的全排列的组合和以5开头的和3,4的全排列的组合.
求全排列和组合问题

 1 #include <
 2 iostream>
 3 using namespace std;
 4 
 5 void Perm(int start, int end, int a[]) {
 6 //得到全排列的一种情况,输出结果
 7 if (start == end) {
 8 for (int i = 0; i < end; i++)
 9 cout << a[i] << ' ';
10 cout << endl;
11 return;
12 }
13 for (int i = start; i < end; i++) {
14 swap(a[start], a[i]); //交换
15 Perm(start + 1, end, a); //分解为子问题a[start+1,...,end-1]的全排列
16 swap(a[i], a[start]); //回溯
17 }
18 }
19 int main() {
20 int i, n, a[10];
21 while (cin >> n, n) {
22 for (i = 0; i < n; i++)
23 {
24 a[i] = i + 1;
25 }
26 Perm(0, n, a);
27 }
28 return 0;
29 }

 

2.组合:C(n,k),n个数中任取k个数
递归法


实际上就是在n个数中,标记k个数,然后输出这k个数的过程。使用一个visited数组来记录相应下标的数是否被选中。

 1 #include <iostream>
 2 using namespace std;
 3 
 4 void dfs(int pos, int cnt, int n, int k, int a[],bool visited[]) {
 5 //已标记了k个数,输出结果
 6 if (cnt == k) {
 7 for (int i = 0; i < n; i++)
 8 if (visited[i]) cout << a[i] << ' ';
 9 cout << endl;
10 return;
11 }
12 
13 //处理到最后一个数,直接返回
14 if (pos == n) return;
15 
16 //如果a[pos]没有被选中
17 if (!visited[pos]) {
18 //选中a[pos]
19 visited[pos] = true;
20 //处理在子串a[pos+1, n-1]中取出k-1个数的子问题
21 dfs(pos + 1, cnt + 1, n, k, a,visited);
22 //回溯
23 visited[pos] = false; 
24 }
25 //处理在子串a[pos+1, n-1]中取出k个数的问题
26 dfs(pos + 1, cnt, n, k, a, visited);
27 }
28 int main() {
29 int i, n, k;
30 while (cin >> n >> k, n || k) 
31 {
32 int *a = new int[n];
33 bool *visited = new bool[n];
34 for (i = 0; i < n; i++)
35 {
36 a[i] = i + 1;
37 visited[i] = false;
38 }
39 dfs(0, 0, n, k, a, visited);
40 delete[] a;
41 delete[] visited;
42 }
43 getchar();
44 return 0;
45 }

‘01’转换法

本程序的思路是开一个数组,其下标表示1到n个数,数组元素的值为1表示其代表的数被选中,为0则没选中。
首先初始化,将数组前n个元素置1,表示第一个组合为前n个数。
然后从左到右扫描数组元素值的“10”组合,找到第一个“10”组合后将其变为“01”组合,同时将其左边的所有“1”全部移动到数组的最左端。
当第一个“1”移动到数组的n-m的位置,即n个“1”全部移动到最右端时,就得到了最后一个组合。
例如求5中选3的组合:
1 1 1 0 0 //1,2,3

1 1 0 1 0 //1,2,4

1 0 1 1 0 //1,3,4

0 1 1 1 0 //2,3,4

1 1 0 0 1 //1,2,5

1 0 1 0 1 //1,3,5

0 1 1 0 1 //2,3,5

1 0 0 1 1 //1,4,5

0 1 0 1 1 //2,4,5

0 0 1 1 1 //3,4,5

 1 #include <iostream>
 2 using namespace std;
 3 
 4 //输出结果
 5 void printRes(int* a, bool* index, int n)
 6 {
 7 for (int i=0;i<n;i++)
 8 {
 9 if (index[i])
10 {
11 cout << a[i] << " ";
12 }
13 }
14 cout << endl;
15 }
16 
17 //检查最后k个位置是否已全变成0
18 bool hasDone(bool* index, int n, int k)
19 {
20 for (int i=n-1;i>=n-k;i--)
21 {
22 if (!index[i])
23 {
24 return false;
25 }
26 }
27 return true;
28 }
29 
30 void Comb(int* a, int n, int k)
31 {
32 bool *index = new bool[n]();
33 //选中前k个位置
34 for (int i = 0; i < k; i++)
35 {
36 index[i] = true;
37 }
38 printRes(a, index, n);
39 
40 while (!hasDone(index, n, k))
41 {
42 //从左到右扫描数组
43 for (int i = 0; i < n - 1; i++)
44 {
45 //找到第一个“10”组合将其变成"01"组合
46 if (index[i] && !index[i + 1])
47 {
48 index[i] = false;
49 index[i + 1] = true;
50 
51 //将"01"组合左边的1移到最左边
52 int count = 0;
53 for (int j = 0; j < i; j++)
54 {
55 if (index[j])
56 {
57 index[j] = false;
58 index[count++] = true;
59 }
60 }
61 printRes(a, index, n);
62 break;
63 }
64 }
65 }
66 delete[] index;
67 }
68 int main()
69 {
70 int n,k;
71 while (cin>>n>>k)
72 {
73 int *a = new int[n]();
74 for (int i = 0; i < n; i++)
75 {
76 a[i] = i+1;
77 }
78 Comb(a, n, k);
79 delete[] a;
80 }
81 
82 return 0;
83 }