组合问题

原创


排列组合问题是算法中很基础又很常用的算法,在我的几篇知识浅薄的博客中也列出了全排列的递归算法,全排列的递归算法

复杂,还有更加优化的算法,过几天我会写新随笔列出;今天,我写了非递归的组合算法,相比于递归的组合算法有所改进,但

是我只是借鉴了大神博客里面的思想,在此附上链接http://www.waitingfy.com/archives/1016

代码是自己编写的,思想水平可能也不高,有错误的地方,请大家指出,赐教了。

解题思路不难理解,用了一种被称为二进制的方法——从N个数中取M个数组合,开辟一个N个空间的数组A,A的数组下标代表了N个

数的下标(N个数存放在另外一个大小为N的数组中),数组A的元素置1,表明选中了这个下标,反之,表示没选中。

问题转换为在数组A中置M个1,不重不漏的找出所有组合的方法如下:

一、先让A中元素全置0,然后将前M个元素置1(代表先选择前M个元素的下标);

二、从A的首元素起向右搜索,当首次遇到当前元素为1,下一个元素为0时,交换两个元素;

三、在二步中将10组合换成01组合后,将元素0前面的所有1元素(假设有T个)全都往前推,直到前T个元素全置为1。

四、此时得到一种组合,可以输出;回到第二步,继续寻找下一种组合,直到A后面的M个元素全部置为1(此时为最后一种组合)。

还是辣个栗子:

从数组 { 1,2,3,4,5 }选出3个元素组合;

数组A的变化为:(蓝色代表10组合的交换,红色代表1的前置)

1 1 1 0 0  —— 7 (我们按权位从左往右计算换成十进制

1 1 0 1 0  —— 11

1 0 1 1 0  —— 13

0 1 1 1 0  —— 14

1 1 0 0 1  —— 19

1 0 1 0 1  —— 21

0 1 1 0 1  —— 22

1 0 0 1 1  —— 25

0 1 0 1 1  —— 26

0 0 1 1 1  —— 28

按照这种方法,发现换成十进制后的数据从小到大排列(当然,也可以反过来——先将A后面的M个元素置1,接下来的步骤反向操作即可)。

从上可知,这种方法从小到大不重不漏的找出了所有的组合数,首步的前M个元素置1即找出了最小组合数,接下来将10组合换成01组合,并且

将0元素前的1置前是为了求次小组合数,通过从左到右的权位不难理解;在次小组合的基础上我们再求次次小的组合数。

写的代码可能不够简洁、简练,主要是提供给大家一个思路:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #define m 3
 4 
 5 int arr[]={2,5,64,10,55,89};
 6 
 7 void combination(int *p,int M)
 8 {
 9     int i;
10     for(i=0;i<=sizeof(arr)/4-1;i++)
11     {
12         if(p[i]==1 && p[i+1]==0)    //找到'10'组合,交换 
13         {
14             p[i]=0;
15             p[i+1]=1;
16             /*
17             int j;
18             int count=0;    //统计交换后0前面有多少个1 
19             for(j=0;j<i;j++)
20             {
21                 if( p[j]==1 )
22                     count++;
23             }
24             for(j=0;j<i;j++)
25                 p[j]=0; 
26             for(j=0;j<count;j++)    //把1前置 
27                 p[j]=1;
28             */
29             int left,right;
30             for(left=0;left<i;left++)    // left代表0,right代表1 
31             {
32                 if( p[left]==0 )
33                 {
34                     for(right=left+1;right<i;right++)
35                     {
36                         if( p[right]==1 )
37                         {
38                             p[left]=1;    //交换 
39                             p[right]=0;
40                             break;
41                         }
42                     }
43                 }
44             }
45             int j;
46             for(j=0;j<=sizeof(arr)/4-1;j++)
47                 if(p[j]==1)
48                     printf("%d ",arr[j]);
49             printf("
");
50             int flag=0;
51             for(j=sizeof(arr)/4-1;j>=sizeof(arr)/4-M;j--)
52             {
53                 if(p[j]==0)
54                     flag=1;
55             }    
56             if(flag==0)
57                 break; 
58             i=-1;    //新的一轮 
59         }
60     }
61 }
62 
63 int main()
64 {
65     int i;
66     int *p=(int *)malloc(sizeof(int)*(sizeof(arr)/4));    
67     for(i=0;i<=sizeof(arr)/4-1;i++)    //置0 
68         p[i]=0;
69     
70     for(i=0;i<=m-1;i++)    //前M位置1
71         p[i]=1;
72     int j;
73     for(j=0;j<=sizeof(arr)/4-1;j++)
74         if(p[j]==1)
75             printf("%d ",arr[j]);
76     printf("
");    
77     combination(p,m);
78     free(p);
79     return 0;
80 } 

2018-04-08

原文地址:https://www.cnblogs.com/chiweiming/p/8735527.html