Combination 组合

问题

从包含nn个元素的集合s=[x0,x1,x2,,xn1]s = [x_0, x_1, x_2, \dots ,x_{n-1} ]中任意取mm个元素(mnm \leq n)组成组合,求所有组合。集合ss中任意两元素互不相同。

解法

设置集合c=[c0,c1,c2,,cm1]c = [ c_0, c_1, c_2, \dots , c_{m-1} ]表示集合ss的选择,ci=1c_i = 1表示选择数字xix_ici=0c_i = 0表示不选择数字xix_i。比如集合s=[x0,x1,x2,,xn1]s = [ x_0, x_1, x_2, \dots, x_{n-1} ]中取出组合

[x0,x1,x2][x_0, x_1, x_2]

等价于集合

c=[10,11,12,03,,0n1]c = [1_0, 1_1, 1_2, 0_3, \dots, 0_{n-1} ]

即元素[c0,c1,c2][ c_0, c_1, c_2 ]11,元素[c3,,cn1][ c_3, \dots, c_{n-1} ]00

可以看出,包含nn个元素的集合s=[x0,x1,x2,,xn1]s = [x_0, x_1, x_2, \dots, x_{n-1} ]中取出mm个元素的所有组合,可以转化为求有ii11mim - i00的集合cc的唯一全排列,其中0im0 \leq i \leq m

(1)(1) 从集合ss中取出00个元素作为组合,即cc中有0011mm00,唯一全排列有C0m=1C_0^m = 1

[][]

(2)(2) 从集合ss中取出11个元素作为组合。则cc中有1111m1m-100,唯一全排列有C1m=mC_1^m = m

[10,01,02,,0n1][00,11,02,,0n1][00,01,12,,0n1][00,01,02,,1n1]\begin{array}{lcr} [ 1_0, 0_1, 0_2, \dots , 0_{n-1} ] \\ [ 0_0, 1_1, 0_2, \dots , 0_{n-1} ] \\ [ 0_0, 0_1, 1_2, \dots , 0_{n-1} ] \\ \cdots \\ [ 0_0, 0_1, 0_2, \dots , 1_{n-1} ] \end{array}

(3)(3) 从集合ss中取出22个元素作为组合,则cc中有2211m2m-200,唯一全排列有C2m=mC_2^m = m个。

只要求出所有唯一全排列,即可反向求出对应的组合。

包含nn个元素中选出mm个元素的所有组合,需要重复m+1m + 1次,每次求有ii11mim - i00的集合cc的唯一全排列,其中i[0,m]i \in [0, m]。根据全排列反向得到组合,算法结束。第ii步求唯一全排列的时间复杂度为O(i!)O(i!),该算法的时间复杂度为O(Cmn)=O(n!m!(nm)!)O(C_m^n) = O(\frac{n!}{m! \cdot (n-m)!})

StackOverflow - algorithm-to-return-all-combinations-of-k-elements-from-n

二项式系数

Chase’s Twiddle - Algorithm 382: Combinations of M out of N Objects:

Buckles - Algorithm 515: Generation of a Vector from the Lexicographical Index:

Remark on algorithm 515: Generation of a vector from the lexicographical index combinations

源码

Combination.h

Combination.cpp

测试

CombinationTest.cpp

Last updated