排列组合n选m,组合算法——0-1转换算法(巧妙算法)C++实现
知识储备
排列的定义:从n个不同元素中,任取m(m≤n,m与n均为自然数,下同)个元素按照一定的顺序排成一列,叫做从n个不同元素中取出m个元素的一个排列;从n个不同元素中取出m(m≤n)个元素的所有排列的个数,叫做从n个不同元素中取出m个元素的排列数,用符号 A(n,m)表示计算公式:
注意:m中取n个数,按照一定顺序排列出来,排列是有顺序的,就算已经出现过一次的几个数。
只要顺序不同,就能得出一个排列的组合,例如1,2,3和1,3,2是两个组合。
组合的定义:从n个不同元素中,任取m(m≤n)个元素并成一组,叫做从n个不同元素中取出m个元素的一个组合;从n个不同元素中取出m(m≤n)个元素的所有组合的个数,叫做从n个不同元素中取出m个元素的组合数。
用符号 C(n,m) 表示。
计算公式:
注意:m中取n个数,将他们组合在一起,并且顺序不用管,1,2,3和1,3,2其实是一个组合。
只要组合里面数不同即可
组合算法
本算法的思路是开两个数组,一个index[n]数组,其下标0~n-1表示1到n个数,1代表的数被选中,为0则没选中。
value[n]数组表示组合
的数值,作为输出之用。
?
首先初始化,将index数组前m个元素置1,表示第一个组合为前m 个数,后面的置为0。
?
然后从左到右扫描数组元素值的“10”组合,找到第一个“10”组合后将其变为?“01”组合,同时将其左边的所有“1”全部移动到数组的最左端。
一起得到下一个组合(是一起得出,是一起得出,是一起得出)重复1、2步骤,当第一个“1”移动到数组的n-m的位置,即m个“1”全部移动到最右端时;即直到无法找到”10”组合,就得到了最后一个组合。
组合的个数为:
例如求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
代码如下:
#include iostream
using namespace std;
void Show(int ,int index[],int value[]);
bool judge(int,int ,int index[]);
void change(int ,int ,int index[],int value[]);
int main()
int i,n,m;
cout"请输入元素个数:";
cout"请输入选多少元素:";
int index[n]={0},value[n]; --index务必初始化为0,不然无法知道m个数之后里面是真还是假
for(i=0;in;i++)
value[i]=i+1;--此处是赋初值,以1,2,3,4,5为例,当然任何数字都可以
change(n,m,index,value);
return 0;
void Show(int n,int index[],int value[])
for(i=0;in;i++)
if(index[i]) ?coutvalue[i]" ";
coutendl;
bool judge(int n,int m,int index[])
for(i=n-1;i=n-m;i--)
if(!index[i]) ?return false;
return true;
void change(int n,int m,int index[],int value[]) ?--核心算法函数
int i,j,num=0;
for(i=0;im;i++)
index[i]=1;
Show(n,index,value); --第一个组合
while(!judge(n,m,index)) ?--只要没使1全部移到右边,就继续循环
for(i=0;in-1;i++) ?--注意是n-1,因为i=n-1时,i+1是不存在的 --找到10,变成01
if(index[i]==1index[i+1]==0)
index[i]=0;
index[i+1]=1;
--将01组合左边的1全部放在数组最左边
int count=0;
for(j=0;ji;j++)
if(index[j])
index[j]=0;
index[count++]=1;
Show(n,index,value); ?--输出
cout"共有"num"种"endl;
quadquad 当a=b=1a=b=1a=b=1时,(a+b)n=2n=∑i=0nCni(a+b)^n=2^n=sum_{i=0}^n
C_n^i(a+b)n=2n=∑i=0n?Cni?;
--- param name="n"Int32类型的正整数-param
x = int( (ws-2) - (self.w-2) )#距屏幕左边框的像素点数
②n个元素被分成K类,每类的个数分别是n1,n2,…,nk这n个元素的全排列数为n!-(n1!xn2!x…xnk!)。
Show(n,m,index,value); ?--输出
permutate(0,3,a);--对数组中前三个数进行排列
package?BeanUtil;
r[j-2] = k-1;
上面的例子实际上展示了动态规划里面所谓的滑动数组(Sliding array),从而大大地降低了空间复杂度,(当然还会有更好的策略)。
-- 然后从左到右扫描数组元素值的“10”组合,找到第一个“10”组合后将其变为。