学习求组合数的算法

来源:互联网 发布:淘宝商城意尔康女靴 编辑:程序博客网 时间:2024/06/10 03:42
网上搜来的:
求组合数的算法:
求解从N个元素中取出R个元素的组合方案和组合数,首先观察一个具体的例子,设N=6,R=3,可以得到其选法为:
(1)1 2 3 (2)1 2 4 (3)1 2 5 (4)1 2 5
(5)1 3 4 (6)1 3 5 (7)1 3 6
(8)1 4 5 (9)1 4 6
(10)1 5 6
(11)2 3 4 (12)2 3 5 (13)2 3 6
(14)2 4 5 (15)2 4 6
(16)2 5 6
(17)3 4 5 (18)3 4 6
(19)3 5 6
(20)4 5 6
从上面组合的生成过程中可以看出如下规律:
(1) 最后一位数最大可达N,倒数第二位最大可达N-1,……,依次类推倒数第K位(K<=N)不得超过N-K+1,因此,若R个元素的组合用C(1)C (2)……C(R)来表示,且设定C(1)<C(2)<……<C(R),则有C(R)<=N-R+1,I=1,2,3,……, R。
(2)当存在C(J)<N-R+J时,其中下标的最大者设为I,即有:
I=MAX{J|C(J)<N-R+J},则有C(I)=C(I)+1。与之相对应地有:
C(I+1)=C(I+1)+1,……,C(R)=C(R)+1
由此,可以得到从一个组合到下一个组合的算法如下:
S1 : 求满足不等式C(I)<N-R+I的最大的数I,即I=MAX{J|C(J)<N-R+J}
S2 : C(I)=C(I)+1
S3 : 从I+1位起开始修改:C(J)=C(J-1)+1;J=I+1,I=2,……,R

我昨天的提示就是小菜壶解释的,他解释的很清楚.
其实列举组合数算法一般有两类:
其一就是你上次用递归写的,叫什么换位法.另一个就是这个.
我把写了一段程序,可以实现上面的算法.
/*
功能:实现任意指定的组合数列举
参数:m是列举数所在集合的元素个数
k是组合数个数.
比如comb(6,3)
就可以把1 2 3 4 5 6
中间的所有三个数的组合按下面的顺序列举出来
1 2 3
1 2 4
1 2 5
1 2 6
1 3 4
1 3 5
1 3 6
1 4 5
1 4 6
1 5 6
2 3 4
2 3 5
2 3 6
2 4 5
2 4 6
2 5 6
3 4 5
3 4 6
3 5 6
4 5 6
Press any key to continue
*/
void comb(int m,int k)
{
int i,j,l;
int finished=0;/*是否列举完毕标志 */
for(i=0;i<k;i++)
C[i]=i+1;
for(i=0;i<k;i++)
printf("%d ",C[i]);
printf("");
while(!finished)
{j=k-1;
while(C[j]>=m-k+j+1)j--;/*自后向前寻找第一个不够大的数的下标*/
l=C[j];
for(i=j;i<k;i++)
{/*从寻找到的下标处始,后面的元素都比前面元素大1*/
C[i]=l+i-j+1;

}
for(i=0;i<k;i++)
printf("%d ",C[i]);
printf("");
if(C[0]==m-k+1)finished=1;/*循环结束条件*/

}
}


多谢楼上两位! 我会想想你们提供的思路的。
关于我的解法的思路,完全是来自<<数据结构,算法C++描述>>
(http://www.chinaedu.edu.cn/cgi-bin/huazhang/anybook.php?bookname=5)
求全排列算法的启发的。
顺便问一下,这本<<数据结构,算法C++描述>>好不好看?这方面有介绍吗?
问题描述:
有元素数目为 m的集合{1, 2, ..., m}.
求元素数目为 n(n < m) 的全部组合。
我的大概思路:
f({a,..b}, n), 指集合{a,..b}中数目为 n的所有组合, 这里 {a,... b} 属于集合m的子集。
当 n = 1;
f({1,m}, 1) 的结果是: {1}, {2}, ..., {m};
当 n = x (x>1);
f({1, m}, n) 的结果是: {1 + f({2, m}, n-1)}, {2, f({3, n}, n-1)}, ..., {m-n, f({m-n, n}, n-1)}
用递归。
这些循环加上递进、回归想起来还相当复杂,有时候想到迷迷糊糊不知方向。
不过很有意思,想着的时候很精神,不会打瞌睡。 ^_^
// 顺便把程序改进一下,避开可以避免的递归调用。
// tc3.0下通过编译.
#include <stdio.h>
void comb(int* ps, int* pe, int elems, int buf[], int bufsz) {
int* pi, i;
if(elems == 1) {
for(pi = ps; pi < pe; pi++) {
for(i = bufsz - 1; i > 0; i--)
printf("%d ", buf[i]);
printf("%d", *pi);
}
return;
}
for(pi = ps; pi < pe - elems; pi++) {
buf[elems - 1] = *pi;
comb(pi + 1, pe, elems - 1, buf, bufsz);
}
if(pi == pe - elems) {
for(i = bufsz - 1; i > elems - 1; i--)
printf("%d ", buf[i]);
for(;pi < pe; pi++)
printf("%d ", *pi);
putc('', stdout);
}
}
int main() {
const int elems = 3;
int buf[3];
int list[] = {1, 2, 3, 4, 5};
comb(&list[0], &list[5], elems, buf, elems);
return(0);
原创粉丝点击