组合问题

组合的实现:

 

1.回溯实现
回溯法实现从1~n这n个数中每次取m个数的组合,设置a数组,i从1开始取值,a(1)从1开始到n取值。约定a(1),...,a(i),...,a(m)按升序排列,a(i)后有m-i个大于a(i)的元素,其中最大取值为n,显然a(i)最多取n-m+i,即a(i)回溯的条件是a(i)=n-m+i。
当i<m时,i增加1,a(i)从a(i-1)+1开始取值,直到i=m时输出结果。
当a(i)=n-m+i时,i--回溯,直到i=0时结束。
代码:

  1. // ICPC.cpp : 定义控制台应用程序的入口点。   
  2. // 排列组合   
  3.   
  4. #include "stdafx.h"   
  5.   
  6. #define MAXN 100   
  7.   
  8. // 组合的回溯实现   
  9. int _tmain(int argc, _TCHAR* argv[])  
  10. {  
  11.         int i, j, n, m, a[MAXN];  
  12.         long s = 0;  
  13.   
  14.         printf("Input n and m: ");  
  15.         scanf("%d%d", &n, &m);  
  16.   
  17.         i = 1; a[1] = 1;  
  18.         while (1)  
  19.         {  
  20.                 if (i == m)  
  21.                 {  
  22.                         s++;  
  23.                         for (j = 1; j <= m; j++)  
  24.                                 printf("%d", a[j]);  
  25.                         printf(" ");  
  26.                 }  
  27.                 else  
  28.                 {  
  29.                         i++;  
  30.                         a[i] = a[i - 1] + 1;  
  31.                         continue;  
  32.                 }  
  33.                 // 调整或回溯   
  34.                 while (a[i] == n - m + i)  
  35.                         i--;  
  36.                 if (i > 0)  
  37.                         a[i]++;  
  38.                 else  
  39.                         break;  
  40.         }  
  41.   
  42.         printf("/ns=%ld/n", s);  
  43.   
  44.         return 0;  
  45. }  

 

2.组合的递归实现

应用递归设计,设comb(int n, int k)为从1~n这n个数中取k个数的所有组合结果。当组合的第一个数字选定时,其后的数字是从余下的n-1个数中取k-1个数的组合。这就是把从n个数中取k个数的组合问题转化为从n-1个数中取k-1个数的组合问题。设置数组a存放求出的组合数字,约定函数将确定的k个数字组合的第一个数字放在a[k]中,当一个组合救出后,才将数组a中的一个组合输出。

代码:

 

  1. // ICPC.cpp : 定义控制台应用程序的入口点。   
  2. // 排列组合   
  3.   
  4. #include "stdafx.h"   
  5.   
  6. #define MAXN 100   
  7.   
  8. int a[MAXN];  
  9.   
  10. // 组合的递归实现   
  11.   
  12. void comb(const int n, const int k)  
  13. {  
  14.         int i, j;  
  15.         for (i = n; i >= k; i--)  
  16.         {  
  17.                 a[k] = i;  
  18.                 if (k > 1)  
  19.                         comb(i - 1, k - 1);  
  20.                 else  
  21.                 {  
  22.                         for (j = a[0]; j > 0; j--)  
  23.                                 printf("%d", a[j]);  
  24.                         printf(" ");  
  25.                 }  
  26.         }  
  27. }  
  28.   
  29. int _tmain(int argc, _TCHAR* argv[])  
  30. {  
  31.         int n, m;  
  32.   
  33.         printf("Input n and m: /n");  
  34.         scanf("%d%d", &n, &m);  
  35.           
  36.         a[0] = m;  
  37.         comb(n, m);  
  38.   
  39.         return 0;  
  40. }  

 

问题提出:在n个不同的元素中取m个允许重复的组合,其组合数为c(n+m-1, m),相当于m个无区别的球放进n个有标志的盒子,每个盒子放的球不加限制的方案数。
设计要点:
为实现可重复的组合,约定1<=a(1)<=a(i)<=a(m)<=n,即按不减顺序排列。当i<m时,i增1,a(i)从a(i-1)开始取值(因为可重复),直至i=m时输出结果。
当a(i)=n时i--回溯(因为组合的每一位置最大都可以取n),直到i=0时结束。

代码:

  1. // ICPC.cpp : 定义控制台应用程序的入口点。   
  2. // 排列组合   
  3.   
  4. #include "stdafx.h"   
  5.   
  6. #define MAXN 100   
  7.   
  8. int a[MAXN];  
  9.   
  10. // 允许重复的组合   
  11.   
  12. int _tmain(int argc, _TCHAR* argv[])  
  13. {  
  14.         int n, m, i, j, a[MAXN];  
  15.         long s = 0;  
  16.   
  17.         printf("Input n and m: ");  
  18.         scanf("%d%d", &n, &m);  
  19.   
  20.         i = 1; a[1] = 1;  
  21.         while (1)  
  22.         {  
  23.                 // 如果i==m就将结果输出   
  24.                 if (i == m)  
  25.                 {  
  26.                         s++;        // 计数加1   
  27.                         for (j = 1; j <= m; j++)  
  28.                                 printf("%d", a[j]);  
  29.                         printf(" ");  
  30.                           
  31.                 }  
  32.                 else  
  33.                 {  
  34.                         i++;  
  35.                         a[i] = a[i - 1];        // a(i)从a(i-1)开始取值,因为数与数之间可以重复   
  36.                         continue;  
  37.                 }  
  38.                 while (a[i] == n)                // 回溯   
  39.                         i--;  
  40.                 if (i > 0)  
  41.                         a[i]++;  
  42.                 else  
  43.                         break;  
  44.         }  
  45.   
  46.         printf("/ns = %d/n", s);  
  47.   
  48.         return 0;  
  49. }  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值