c++编程 从n个数中选出m个数进行组合
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++编程 从n个数中选出m个数进行组合相关的知识,希望对你有一定的参考价值。
#include<iostream>
#include<cmath>
#include<vector>
using namespace std;
void f(int *a,int n,int m,vector<int> result);
int main()
int num,n,m;
int i;
cin>>num;
while(num--)
cin>>n>>m;
int *a=new int[n];
for(i=0;i<n;i++)
a[i]=i+1;
vector<int> result;
f(a,n,m,result);
return 0;
void f(int *a,int n,int m,vector<int> result)
int i,j,temp;
for(i=0;i<n;i++)
temp=a[i];
if(a[i]!=0)
result.push_back(a[i]);
a[i]=0;
if(m>1)
f(a,n,m-1,result);
else
for(j=0;j<result.size();j++)
cout<<result[j];
cout<<endl;
result.pop_back();
a[i]=temp;
求大神解释下此代码
编程思路:
从n个数中选出m个数进行组合(n>m)可以采用递归的方式解决
先从n个数中选一个数出来,然后在剩下的n-1个数当中选取m-1个数进行组合
对于n-1个数,同样有
先从n-1个数中选一个数出来,然后在剩下的n-2个数当中选取m-2个数进行组合
...
对于n-N个数,同样有
先从n-N个数中选一个数出来,然后在剩下的n-N个数当中选取m-N个数进行组合
如此递归
直到m-N==1为止
当m-N为1的时候,自然不用选了
每次选取的结果放入一个数组当中,作为参数传递下去
当递归到m-N为1的时候,数组和当前选定的值即构成一个有效组合,便可输出
这类问题都可以尝试递归的解决思路,将一个复杂的大问题,一级一级转化为较小的,可以解决的问题
示例代码如下:
void select(int* data/*待筛选的数 里面不能有重复的数*/,
int n,
int m,
int list[]/*假设list长度足够,为m,初始list中的元素值为-1*/,
int listlen)
int i,j;
if(m==1)
for(i=0;i<n;i++)
for(j=0;list[j]!=-1;j++)
printf("%d ",list[j]);
printf("%d\\n",data[i]);//输出一个结果
return;
for(int i=0;i<n-m;i++)
list[listlen-m] = data[i];
select(data+i+1,n-i,m-1,list,listlen);//递归调用
参考技术A n = 5
m = 3
a数组 result向量
1,2,3,4,5
0,2,3,4,5 1
0,0,3,4,5 1,2
0,0,0,4,5 1,2,3 //输出,回溯
0,0,3,0,5 1,2,4 //输出,回溯
0,0,3,4,0 1,2,5 //输出,回溯
0,2,0,4,5 1,3
0,0,0,4,5 1,3,2 //输出,回溯
0,2,0,0,5 1,3,4 //输出,回溯
。。。。。。 //这是排列,不是组合
自己单步运行调试吧,这样更容易理解追问
我的编译器有问题 亲 可不可以给我一个呀
追答我手上只有VS 镜像,这太大了,没法给, 你还是网上搜搜吧。 祝好运
追问谢谢啦 我也被我的vc干死了
本回答被提问者采纳集训DAYn——组合数学
组合,吼吼吼
又到了我们信息老师讲数学课了,吼吼吼
然后数学老师中途探望了一下,哇塞塞,然后他看到黑板上的题,微妙的笑了.
排列:从n个数中有序的选出m个数的方案数是多少?
第一个数有n种取法,第二个数有n-1种取法......第m个数有n-m+1种取法。
n*(n-1)*...*(n-m+1)=n!/(n-m)!记为A(n,m).
组合:从n个数中无序的选出m个数的方案数是多少?
先有序的取m个数,那么无序的m个数会被取到m!次。
A(n,m)/m!=n!/[m!(n-m)!]记为C(n,m)
C(n,m)=C(n-1,m)+C(n-1,m-1).
组合数的性质:1.C(m,n)=C(n-m,n)
2.C(m,n)=C(m,n-1)+C(m-1,n-1)
3.C(0,n)+C(1,n)+C(2,n)+...+C(n,n)=2^n
4.C(n,n)+C(n,n+1)+C(n,n+2)+...+C(n,n+r)=C(n+1,n+r+1)
5.C(0,n)+C(2,n)+C(4,n)+...=C(1,n)+C(3,n)+C(5,n)+...=2^(n-1)
something else
1.n个人围着一张圆桌坐在一起,共有(n-1)! 种坐法。
2.从n个排成一排的数中取m个数,且数字之间互不相邻,共有C(m,n-m+1)种取法。
二次项定理:
(a+b)^n=∑(0<=k<=n)C(k,n)*(a^k)*(b^(n-k))
友情证明:可爱的数学归纳法
当n=1时,(a+b)^1=C(0,n)*(a^0)*(b^1)+C(1,n)*(a^1)*(b^0)=a+b成立
假设当n=m时命题成立,当n=m+1时:
(a+b)^(m+1)=(a+b)(a+b)^m
=(a+b)∑(0<=k<=n)C(k,m)*(a^k)*(b^(m-k))
=...=∑(0<=k<=m+1)C(k,m+1)*(a^k)*(b^(m+1-k))
那么,二次项定理有什么用呢?
我可以负责任的告诉你,这个数学里是经常考的,2017年的浙江高中数学省赛卷第一题就是这个东西,它可以被用于证明可爱的费马小定理...我知道你心里已经开始喊停了...
但数学和信息是分不开的,数学班的同学告诉我们数学老师在数学班里讲树还有剪枝,数学奥林匹克命题人讲座(简称命题人)的《组合问题》的编写者之一就是毕业于计算机系的...
所以还是对数学好点吧。
讲正事,想知道浙江省省赛卷第一题是怎么出的吗?(不想知道,我还是会讲)
二次项定理的直接运用,不要你计算,我们把他变成信息题,如下:
给定一个多项式(ax+by)^k,求出多项式展开后的x^n*y^m项的系数,对10007取模。
0<=n,m<=k<=1000,n+m=k,0<=a,b<=1000000。
根据二次项定理,有(ax+by)^k=∑(0<=i<=k)C(i,k)*(a^i)*(b^(k-i))*(x^i)*(y^(k-i))
所以(x^n)*(y^m)的系数即为C(n,k)*(a^n)*(b^m),直接计算就好。
数学题是不是很简单,只不过算的很烦,然而信息就不存在这种问题了,所以我爱信息,呦吼吼!
隔板法
隔板法又称插空法,就是在n个元素间插入(m-1)个板,即把n个元素分成m组的方法。
eg:
n个球和m个袋子,已经有大佬总结得可好了,棒棒_qwq_(颜文字中毒期)
这里呢我们再小小的分析一下球和袋子的问题
1.将n个不同的球放到m个相同的袋子里有多少种方案(没有空袋子哦)?
用f[i][j]表示将i个不同的球放到j个相同的袋子,并保证每个袋子里都有球的方案数。
我们考虑第i个球是不是单独放的,f[i][j]=f[i-1][j-1]+f[i-1][j]*j
答案是f[n][0]+f[n][1]+...f[n][m].时间复杂度是O(nm)
以上为ppt原话,反正我是没怎么懂那个式子是怎么出来的,各位大佬可能懂了吧,我太菜了啊~~~
那么,不懂的和我一样的蒟蒻们看看一看一下思路吧:(来自一位蒟蒻的分享)
f[i][j]表示将i个不同的球放到j个相同的袋子中,
假设前面的i-1个球都放好了,放在了j个袋子里,其方案数为f[i-1][j],此时还有一个球要和哪一坨球同居呢?有j个袋子,有j种选择,所以为f[i-1][j]*j(乘法原理,不要告诉我你不会,这真的是小学数学) 。
假设前i-1个球放在了j-1个袋子里,那么第i个球一定在剩余的空袋子里(保证每个袋子里都有球)已有的方案数为f[i-1][j-1].
加一加,就得到了大佬ppt上的式子:f[i][j]=f[i-1][j-1]+f[i-1][j]*j
2.将n个相同的球放在m个相同的袋子里有多少种方案?
由于袋子是相同的,我们通过保证球数是单调不减的来防止重复统计。用f[i][j]表示将i个相同的球放到j个相同的袋子里的方案数。
考虑第一个袋子是否放球,如果放的话,由于球数单调不减,我们必须在每个袋子里都放一个球。
如果不放的话,那我们直接考虑后面的袋子。
f[i][j]=f[i-j][j]+f[i][j-1].时间复杂度O(nm)
以上是关于c++编程 从n个数中选出m个数进行组合的主要内容,如果未能解决你的问题,请参考以下文章
编程求解,输入两个整数n和m,从数列1,2,3,……n中随意取几个数,使其和等于m。要求将所有的可能组合列出来