免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 6968 | 回复: 7
打印 上一主题 下一主题

[C] 求一个计算排列组合的算法 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-08-10 13:29 |只看该作者 |倒序浏览
5可用积分
别告诉我去baidu,google之类的,如果你调试过给我发一下。

最佳答案

查看完整内容

我知道一种非递归的高效率的球组合数方法,基本描述如下(没有证明,但经过acm的多次考验都是正确的)假设5个元素取3个,以数组s表示该位置上的元素是否被选中,1选中,0没有选中。初始为 ,表示第一个组合为前n个数。 1 1 1 0 0 // 1,2,3然后循环,每次从左到右扫描数组元素值的“10”组合,找到第一个“10”组合后将其变为 “01”组合,同时将其左边的所有“1”全部移动到数组的最左端,此时便得到了一个新的组合重复 ...

论坛徽章:
0
2 [报告]
发表于 2009-08-10 13:29 |只看该作者
我知道一种非递归的高效率的球组合数方法,基本描述如下(没有证明,但经过acm的多次考验都是正确的)
假设5个元素取3个,以数组s表示该位置上的元素是否被选中,1选中,0没有选中。
初始为 ,表示第一个组合为前n个数。     
1 1 1 0 0      // 1,2,3
然后循环,每次从左到右扫描数组元素值的“10”组合,找到第一个“10”组合后将其变为  
  “01”组合,同时将其左边的所有“1”全部移动到数组的最左端,此时便得到了一个新的组合
重复这一直到找不到“10”组合:

1 1 [1 0] 0  => 1 1 [0 1] 0  //1,2,4

1 [1 0] 1 0 =>  1 [0 1] 1 0 //1,3 ,4
......
....
0 0 1 1 1 // 3,4,5
以上的例子没有出现“同时将其左边的所有“1”全部移动到数组的最左端”这种情况,具体来说如下:
假设出现了   0 1 [1 0]则要2部变换,先是0 1 [0 1] 再是   [1 0] 0 1

论坛徽章:
0
3 [报告]
发表于 2009-08-10 16:46 |只看该作者

  1. void permutate(char* str, int begin, int end)
  2. {
  3.   int i;
  4.   if(begin == end)
  5.     printf("%s\n",str);
  6.   else
  7.    {
  8.      for(i=begin; i<end; i++)
  9.       {
  10.         swap(str+begin,str+i);
  11.         permutate(str, begin+1, end);
  12.         swap(str+begin,str+i);            
  13.       }               
  14.    }     
  15. }
复制代码

要这种?

论坛徽章:
0
4 [报告]
发表于 2009-08-10 16:49 |只看该作者
不要递归的,只需要给个组合计算的就行了,不考虑排列的了。

论坛徽章:
0
5 [报告]
发表于 2009-08-10 17:33 |只看该作者
相当牛,没调试过是不是不能发给您老人家

论坛徽章:
0
6 [报告]
发表于 2009-08-10 19:11 |只看该作者
std::next_permutation不就得了?

论坛徽章:
0
7 [报告]
发表于 2009-08-10 21:14 |只看该作者
原帖由 mcemil 于 2009-8-10 17:53 发表
我知道一种非递归的高效率的球组合数方法,基本描述如下(没有证明,但经过acm的多次考验都是正确的)
假设5个元素取3个,以数组s表示该位置上的元素是否被选中,1选中,0没有选中。
初始为 ,表示第一个组合为 ...

你说的是这个吧,网上找的,有点问题,不过我已经调试好了,还加了打印,文件记录,代码风格很不好,再整理下

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "stdafx.h"

  5. /***********************

  6. * 计算一个集合的组合

  7. **********************/

  8. #include<stdlib.h>


  9. /*输出某个组合*/

  10. void OutputCom(FILE *fp,const int elements[], int *flags, int length)

  11. {

  12.          int i;
  13.        
  14.          for(i=0; i<length; i++)

  15.          {

  16.                    if(flags[i]==1)

  17.                    {
  18.                                                         //printf("%d ",elements[i]);

  19.                                                         fprintf(fp, "%u ",elements[i] );


  20.                    }

  21.          }
  22.                  //printf("\n");

  23.          fprintf(fp, "\n");

  24. }

  25. /*计算组合*/

  26. int GenCom(FILE *fp,const int elements[], int setLg, int k)

  27. //elements:集合元素; setLg:集合长度; k:从集合中要选取的元素个数

  28. {

  29.          if(k>setLg || k<=0)

  30.                    return -1;



  31.          int i,j;                   //循环变量

  32.          int has10; //是否有"10"组合的标志:1-有;0-无

  33.          int bound; //第一个"10"组合的索引

  34.          int num1;           //"10"组合左边的"1"的个数

  35.          int *flags = (int *)malloc(setLg*sizeof(int));//与元素集合对应的标志:1-被选中;0-未被选中

  36.          //初始化,将标志的前k个元素置1,表示第一个组合为前k个数
  37.                 printf("正在生成......\n");
  38.          for(i=0; i<k; i++)

  39.                    flags[i]=1;

  40.          for(i=k; i<setLg; i++)

  41.                    flags[i]=0;



  42.          OutputCom(fp,elements, flags, setLg);//输出初始化的组合

  43.          /*

  44.                    从左到右扫描标志的"10"组合,找到第一个"10"组合后将其变为"01"组合,同时将其左边的所有"1"全部移动到数组的最左端

  45.          */

  46.          while(1)

  47.          {

  48.                    num1 = 0;

  49.                    has10= 0;

  50.                    for(i=0; i<setLg-1; i++)

  51.                    {

  52.                             if(flags[i]==1 && flags[i+1]==0)//找到第一个"10"组合

  53.                             {

  54.                                      bound = i;



  55.                                      flags[i]=0;//将该"10"组合变为"01"组合

  56.                                      flags[i+1]=1;



  57.                                      for(j=0; j<num1; j++)//将其左边的所有"1"全部移动到数组的最左端

  58.                                      {

  59.                                                flags[j]=1;

  60.                                      }

  61.                                      for(j=num1; j<bound; j++)

  62.                                      {

  63.                                                flags[j]=0;

  64.                                      }



  65.                                      has10 = 1;

  66.                                      break;

  67.                             }

  68.                             else if(flags[i]==1)

  69.                             {

  70.                                      num1++;

  71.                             }

  72.                    }

  73.                    if(has10==0)//没有"10"组合了,代表组合计算完毕

  74.                             break;

  75.                    OutputCom(fp,elements, flags, setLg);

  76.          }

  77.          

  78.          return 1;

  79. }

  80. int ComputeCom( int nSpaceNum, int nElemNum )
  81. {
  82.         int j;
  83.         int denominator = 1;
  84.         int numerator = 1;
  85.         int nCompNum = 1;
  86.         if ( 0 == nElemNum )
  87.         {
  88.                 return 1;
  89.         }
  90.         if ( nElemNum > nSpaceNum / 2 + 1)
  91.         {
  92.                 nElemNum = nSpaceNum - nElemNum;
  93.         }
  94.         //计算单个组合的个数
  95.         for( j = 1; j <= nElemNum; j++ )
  96.         {
  97.                 numerator *= (nSpaceNum - (j-1));
  98.                 denominator *= j;
  99.         }
  100.         nCompNum = numerator / denominator;
  101.         return nCompNum;
  102. }

  103. /*测试*/

  104. int main()

  105. {
  106.         int dwAllComNum;
  107.         FILE *fp;
  108.         const int elements[33]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33};
  109.         int setLg=33;
  110.         fp = fopen("f:/All.txt","w");
  111.         if (NULL == fp)
  112.         {
  113.                 printf("打开文件失败");

  114.                 return -1;
  115.         }


  116.         dwAllComNum = ComputeCom(33,6);
  117.         printf("共有 %d 种组合\n",dwAllComNum);
  118.                  getchar();

  119.          GenCom(fp,elements, setLg, 6);
  120.                  fclose(fp);

  121.         printf("运行完毕\n");
  122.                  getchar();
  123.          return 0;

  124. }


复制代码

论坛徽章:
0
8 [报告]
发表于 2009-08-10 21:16 |只看该作者
原帖由 bidongliang 于 2009-8-10 19:11 发表
std::next_permutation不就得了?

要纯c的,没写清除要求,大家的思维还真广阔
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP