排列问题 = 排列计数 + 排列枚举
- 第一个例子 “abcd” 的全排列?(字符串的全排列)
//采用依次插空排序的方法
#include<iostream>
#include<string>
using namespace std;
int calc(string p,int k) //将排列好的数据存储在 p 中,k代表下标移动的值
{
if(k== p.length()-1)
{
cout<<p<<endl;
return 0;
}
char temp;
for(int i= k;i<p.length();i++)
{
temp = p[k];
p[k] = p[i];
p[i] = temp;//首先进行交换
calc(p,k+1); // 然后进行递归
temp = p[k];//然后回溯 保证字符串出该层循环的时候还是原来的字符串
p[k] = p[i];
p[i] = temp;
}
return 0;
}
int main()
{
string s = "asd";
calc(s,0);
return 0;
}
这里有个问题,插空的时候,为什么直接让 i = k 呢?为什么只向后进行排列而不与前面进行排列呢?
因为 k 是不断从前往后的,所以第k个元素一定与其后的所有元素进行过交换了。
所以下一个元素不必再与前一个元素进行交换。
- 第二个例子
小明最近喜欢搭数字积木。一共有10块积木,每个积木上有一个数字,0~9。
搭积木规则:
每个积木放到其它两个积木的上面,并且一定比下面的两个积木数字小。
最后搭成4层的金字塔形,必须用完所有的积木。
下面是两种合格的搭法:
0
1 2
3 4 5
6 7 8 9
0
3 1
7 5 2
9 8 6 4
请你计算这样的搭法一共有多少种?
思路 : 暴力枚举 (全排列 条件判断)
可以转化成一维的,题目转换为 对0-9 进行全排列。
组合问题 = 组合计数 + 组合枚举
组合计数
- 问题1 m个 中 取n 个,有多少种取法?
递归公式 f(m,n) = f(m-1,n-1) + f(m-1,n-1)
假设 m 中有一个特殊,若这个没取 ,为(m-1,n)
若这个取了 ,为(m-1,n-1)
#include<iostream>
using namespace std;
int calc(int m, int n)//m个球中取 n 个
{
if (m<n)return 0;
if (n == 0)return 1;
if (m == n)return 1;
return calc(m - 1, n - 1) + calc(m - 1, n);
}
int main()
{
int s = calc(3, 2);
cout << s << endl;
}
问题二
若有重复元素
例如 问题:AAABBCCCCDD 中取3个,所有取法?可以全排进行筛选
实际应用
X星球要派出一个5人组成的观察团前往W星。
其中:
A国最多可以派出4人。
B国最多可以派出2人。
C国最多可以派出2人。
D国最多可以派出1人。
E国最多可以派出1人。
F国最多可以派出3人。
那么最终派往W星的观察团会有多少种国别的不同组合呢?
与上题类似
计数枚举的框架
问题