知识储备
1.排列
排列的定义:从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是两个组合。
2.组合
组合的定义:从n个不同元素中,任取m(m≤n)个元素并成一组,叫做从n个不同元素中取出m个元素的一个组合;从n个不同元素中取出m(m≤n)个元素的所有组合的个数,叫做从n个不同元素中取出m个元素的组合数。用符号 C(n,m) 表示。
计算公式:
注意:m中取n个数,将他们组合在一起,并且顺序不用管,1,2,3和1,3,2其实是一个组合。只要组合里面数不同即可
学习组合算法:https://blog.csdn.net/huang1600301017/article/details/88769270
学习全排列算法:https://mp.csdn.net/postedit/88770980
建议先学习以上两个算法再学习这篇博客
组合算法是找出不同的组合序列,全排列算法是对一组序列按照一定顺序进行排列。
从n个元素中选m个元素进行排列组合,就是组合算法+全排列算法。即先在n个元素中用组合算法找出不同的组合,再用全排列算法对选出来的组合进行全排列。
例如:1,2,3,4,5,5个元素选出3个进行排列组合,共有
1 2 3
1 2 4
1 3 4
2 3 4
1 2 5
1 3 5
2 3 5
1 4 5
2 4 5
3 4 5
10种组合,再对上面每一小组组合进行全排列,所有的组合不就是排列组合的结果吗。共有60种。
代码:
#include <iostream>
using namespace std;
void Show(int ,int ,int index[],int value[]); //组合算法系列、排列算法系列
bool judge(int,int ,int index[]); //组合算法系列
void change(int ,int ,int index[],int value[]); //组合算法系列
void Perm(int ,int ,int arr[]); //排列算法系列
int perm_number = 0;
int main()
{
int i,n,m;
cout<<"请输入元素个数:";
cin>>n;
cout<<"请输入选多少元素:";
cin>>m;
int index[n]={0},value[n]; //index务必初始化为0,不然无法知道m个数之后里面是真还是假
for(i=0;i<n;i++)
{
value[i]=i+1;//此处是赋初值,以1,2,3,4,5为例,当然任何数字都可以
}
change(n,m,index,value);
cout<<"共有"<<perm_number<<"种排列组合"<<endl;
return 0;
}
void Show(int n,int m,int index[],int value[])
{
int i,count=0;
int arr[m];
for(i=0;i<n;i++)
{
if(index[i])
{
arr[count++]=value[i]; //将选出来的组合赋值给一个数组,为全排列做准备
}
}
//已经有组合出来了,开始进行全排列
Perm(0,m,arr);
}
bool judge(int n,int m,int index[])
{
int i;
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;i<m;i++)
{
index[i]=1;
}
Show(n,m,index,value); //第一个组合
num +=1;
while(!judge(n,m,index)) //只要没使1全部移到右边,就继续循环
{
for(i=0;i<n-1;i++) //注意是n-1,因为i=n-1时,i+1是不存在的
{
//找到10,变成01
if(index[i]==1&&index[i+1]==0)
{
index[i]=0;
index[i+1]=1;
//将01组合左边的1全部放在数组最左边
int count=0;
for(j=0;j<i;j++)
{
if(index[j])
{
index[j]=0;
index[count++]=1;
}
}
Show(n,m,index,value); //输出
num +=1;
break;
}
}
}
cout<<"共有"<<num<<"种组合"<<endl;
}
//全排列算法
void Perm(int start,int end,int arr[]) //这里相当于递归算法,
{
//道理start=end时,就相当于这次递归结束,找到了一个排列组合
if(start == end)
{
for(int i=0;i<end;i++)
{
cout<<arr[i]<<" ";
}
cout<<endl;
perm_number +=1;
return ;
}
for(int i=start;i<end;i++)
{
swap(arr[start],arr[i]);//假设3,4,5为例,3P(4,5)是已经一个组合,后面则是4P(3,5),5P(3,4),因此需要交换一下
Perm(start+1,end,arr);//相当于P(4,5)
swap(arr[i],arr[start]);//回溯,把顺序还原,不然就破坏了数据,排列就进行不下去了
}
}