面试题: 已知一个含有n个不同元素的集合,要求打印其所有具有k个元素的子集(不允许有重复的)...

TX面试题2: 已知一个含有n个元素的集合,要求打印其所有具有k个元素的子集(不允许有重复的)

 

题目分析, 为了便于说明,不妨将问题简化一下:

    已知一个盒子中有n个不同的球,分别标记为{a1,a2,...,an},现在需要从中取出其中任意k个球,求给出各种组合。

 

首先,从组合数学的角度,我们可以知道本问题是一个典型的不放回组合问题,总的个数为 c(n,k).

对于{a1,a2,...,an}中某一个元素 ai是否出现在k元子集中可以把问题分为如下两个子问题。

(1) 如果ai出现在k元子集中,那么需要在剩下的 n-1个球中选出 k-1个球

(2) 如果ai没有出现在k元子集中,那么需要在剩下的n-1个球中选出k个球

既有: c(n,k) = c(n-1,k-1) + c(n-1,k)

在有该理论的基础上,我们现在的目标就是利用递归调用,当取出的球的个数满足k,则将结果打印即可。

 

为了好说明,我们将本问题再次简化一下, 如果已知n元素为连续集合[1,n], 那么递归程序为:

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 #define N 1000
 5 int a[N]={0}; // 用于存储选中的元素 
 6 int final_k;  // 用于记录k元子集的大小
 7  
 8 /***********************************
 9  * combination 函数中仅使用了a数组,而没有使用辅助数组,
10  * 这是由于默认原始 N元集合为 {1,2,...,n}。 
11 ************************************/
12 void combination(int a[],int n,int k)
13 {
14      for(int i=n;i>=k;i--)
15      {
16          a[k] = i;
17          if(k>1)
18            combination(a,i-1,k-1);  // 不足final_k个元素,递归选取 
19          else
20          {
21              for(int j=a[0];j>0;--j)  // 取出足够多球,打印之 
22                  printf("%d ",a[j]);
23              printf("\n");
24          }
25      }
26 }
27 
28 int main()
29 {
30     int n,k;
31     printf("please input n and k: \n");
32     scanf("%d%d",&n,&k);
33     final_k =k;   
34     combination(a,n,k);
35     return 0;
36 }

 

如果是非连续的n个数呢,那么在combination中需要用到辅助数组了:

tips: 由于LZ我有点懒,所以在输入n个数的时候,默认是不同的数,并没有判断是否有相同的元素。如果大伙儿想去重,请自行添加!

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 #define N 1000
 5 int a[N]={0};    // 原N元素集合 
 6 int b[N]={0};    // 辅助数组,用于存储当前选取的元素,便于打印 
 7 int final_k;     // 用于记录k元素子集是否满足 
 8 
 9 void combination(int a[],int n,int k)
10 {
11      for(int i=n;i>=k;i--)  // 由于是求k元素的组合,所以默认首元素的可能按照数组中顺序有n-k种 
12      {
13          b[k] = a[i];  // 将a[i] 放入到数组b中记录 
14          if(k>1)       // 取出的个数不足final_k个 
15            combination(a,i-1,k-1); 
16          else          // 取出足够个数的球,打印结果 
17          {
18              for(int j=final_k;j>0;--j)
19                  printf("%d ",b[j]);
20              printf("\n");
21          }
22      }
23 }
24 
25 int main()
26 {
27     int a[N]={0};
28     int n,k;
29     printf("please input n and k: \n");
30     scanf("%d%d",&n,&k);
31     for(int i=1;i<=n;i++) scanf("%d",&a[i]);  //输入n个不同的元素
32     final_k =k;   
33     combination(a,n,k);
34     system("pause");
35     return 0;
36 }
random sequence

 

 转载请注明出处:http://www.cnblogs.com/double-win 

转载于:https://www.cnblogs.com/double-win/p/3653004.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值