利用递归生成组合数C(n,m)

简介: /*===================================== 数的组合问题。从1,2,…,n中取出m个数,将所有组合按照字典顺序列出。 如n=3,m=2时,输出: 1 2 1 3 2 3 这里只考虑从互不相同的n个数当中选择m个的情况。
/*=====================================
数的组合问题。从1,2,…,n中取出m个数,将所有组合按照字典顺序列出。
如n=3,m=2时,输出:
1 2
1 3
2 3

这里只考虑从互不相同的n个数当中选择m个的情况。
我的思路:
这里采用的思路和上回解决递归生成全排列的思路差不多。
从a数组的n个数当中选m个到ans数组。
每一次选择一个数到ans[i]时都在a数组中扫描并依次选择所有的可能。
但是这里扫描的范围是从ans[i-1]在a中的下标k的下一个开始,一直扫描到n-(m-i-1)的前一个位置为止。
这个范围是ans[i]的可能选择的范围。(后面还要选一部分才凑够m个数,故不能扫描到a数组的末尾。)
======================================
*/
 1 #include<stdio.h>
 2 int count=0;
 3 void fun(int a[],int n,int m,int i,int k,int ans[]);
 4 //原始数组a[],从a数组的n个数当中选m个数,结果放在ans数组。
 5 //i表示当前要选取第i个数。i从0开始。k表示上一次选取的数在a数组当中的下标。
 6 //最开始时k==-1,表示还没选数据。 
 7 int main()
 8 {
 9     int n,m,a[30],ans[30],i;
10     freopen("5.out","w",stdout);
11     scanf("%d%d",&n,&m);
12     for(i=0;i<n;i++)
13     {
14         //scanf("%d",&a[i]);
15         a[i]=i+1;
16     }
17     fun(a,n,m,0,-1,ans);
18     printf("%d\n",count);
19     return 0;
20 }
21 void fun(int a[],int n,int m,int i,int k,int ans[])
22 //原始数组a[],从a数组的n个数当中选m个数,结果放在ans数组。
23 //i表示当前要选取第i个数。i从0开始计数。k表示上一次选取的数在a数组当中的下标。
24 //最开始时k==-1,表示还没选数据。 
25 {
26     int j;
27     if(i==m)
28     {
29         for(j=0;j<m;j++)    printf("%d ",ans[j]);
30         printf("\n");
31         count++;
32         return ;
33     }
34     else
35     {
36         for(j=k+1;j<n-(m-i-1);j++)//从第k+1个开始,尝试选择第i个数。(注意:i从0开始计算)
37         {
38             ans[i]=a[j];
39             fun(a,n,m,i+1,j,ans);
40         } 
41     }
42 }
View Code

 

 

下面是网上的做法,思路挺好的。

来源:http://blog.csdn.net/challenge_c_plusplus/article/details/6641950

原文如下:

此法借鉴了2009年华为一笔试题我写的一个递归算法

http://blog.csdn.net/challenge_c_plusplus/article/details/6640530

排列数的递归实现见我的另一篇

http://blog.csdn.net/challenge_c_plusplus/article/details/6574788

 1 /*
 2 *    功能:输出组合数C(n,m)
 3 *    日期:2011/7/28
 4 *    作者:milo
 5 *    不足:对于有多个重复数字,会输出重复的组合数,可以通过遍历一个数组链表解决。
 6 */
 7 
 8 #include<stdio.h>
 9 #include<stdlib.h>
10 
11 int *dst_array,top=0,count=0;//中间数组,存放中间求解过程,count计数所有的组合个数
12 
13 //打印长度为n的数组元素
14 static void printA(int *parray,int n)
15 {
16     int i;
17     for(i=0;i<n;i++){
18         printf("%d ",parray[i]);
19     }
20 }
21 
22 //递归打印组合数
23 static  void print_combine(int *pArray,int n,int m)
24 {
25     if(n < m || m==0)    return ;//情况一:不符合条件,返回
26     print_combine(pArray+1,n-1,m);//情况二:不包含当前元素的所有的组合
27     dst_array[top++]=pArray[0];//情况三:包含当前元素
28     if(m==1){//情况三-1:截止到当前元素
29         printA(dst_array,top);
30         printf("\n");
31         count++;
32         top--;
33         return;
34     }
35     print_combine(pArray+1,n-1,m-1);//情况三-2:包含当前元素但尚未截止
36     top--;//返回前恢复top值
37 }
38 
39 int main()
40 {
41     int n,m,*parray;//存放数据的数组,及n和m
42     scanf("%d%d",&n,&m);
43     parray=(int *)malloc(sizeof(int)*n);
44     dst_array=(int *)malloc(sizeof(int)*m);
45     int i;
46     for(i=0;i<n;i++){//初始化数组
47         scanf("%d",&parray[i]);
48     }
49     print_combine(parray,n,m);//求数组中所有数的组合
50     printf("=====C(%d,%d)共计:%d个=====",n,m,count);
51     return 0;
52 }
View Code

 

相关文章
|
机器学习/深度学习
求n的阶乘(递归法和循环法
根据阶乘的计算方法:n!= 1 * 2 * 3*…*n,我们在一个for循环完成 n 次乘法运算。注意因为是连乘,最终阶乘结果可能会非常大所以我们在Fac函数中用 long long 类型的变量来记录阶乘的结果。
利用递归求斐波纳契数列的和
递归的方法更加简单,更容易理解
|
算法
【递归与递推 3】AcWing 717. 简单斐波那契(求解斐波那契数列的若干方法)
【递归与递推 3】AcWing 717. 简单斐波那契(求解斐波那契数列的若干方法)
【递归与递推 3】AcWing 717. 简单斐波那契(求解斐波那契数列的若干方法)
汉诺塔问题, 用递归方法求集合中的中位数
汉诺塔问题, 用递归方法求集合中的中位数
|
机器学习/深度学习 算法
斐波拉契数列的递推递归求解算法
斐波拉契数列的递推递归求解算法
100 0
|
算法
递归+回溯求解数独问题
导读:回溯是常用的算法理论之一,很多规模较大、直接分析较为复杂的问题都可以考虑用回溯求解,例如N皇后问题、骑士周游和走迷宫问题等。本质上,回溯问题是一种优化后的暴力求解,通过及时的剪枝和启发式的寻找最优路径,可以有效加速求解过程。回溯还常常与递归搭配使用
147 0
递归+回溯求解数独问题
|
机器学习/深度学习
递归和非递归实现规律函数
递归和非递归实现规律函数
124 0
【递归】斐波那契数列第n个数
递归、递推计算斐波那契数列第n项的值: 1 #include 2 long long fact(int n); //【递推】计算波那契数列第n个数 3 long long fact2(int n);//【递归】 4 int main(int argc, char *arg...
1094 1