将N个元素的每个子集划分为K个桶的算法

时间:2017-05-21 14:05:47

标签: c# algorithm

我试图实现的方法就像

/*
    e.g. {1, 2, 3}, k = 2

    ---> 

        [ (), () ],
        [ (1), () ],
        [ (), (1) ],
        [ (2), () ],
        [ (), (2) ],
        [ (3), () ],
        [ (), (3) ],
        [ (1), (2) ],
        [ (2), (1) ],
        [ (1), (3) ],
        [ (3), (1) ],
        [ (2), (3) ],
        [ (3), (2) ],
        [ (1,2), () ],
        [ (2,3), () ],
        [ (1,3), () ],
        [ (), (1,2) ],
        [ (), (1,3) ],
        [ (), (2,3) ],
        [ (1,2), (3) ],
        [ (2,3), (1) ],
        [ (1,3), (2) ],
        [ (3), (1,2) ],
        [ (1), (2,3) ],
        [ (2), (1,3) ],
        [ (1,2,3), () ],
        [ (), (1,2,3,) ]

*/

    public static List<List<T>> SpecialPartition<T>(this List<T> source, int k)
    {
        throw new NotImplementedException();
    }

我首先想知道是否有一些已知的(Donald Knuth?)算法。注意桶的顺序如何重要,例如我认为(1,2), (3)(3), (1,2)是单独的结果。

1 个答案:

答案 0 :(得分:3)

请注意,每个元素都可以占用(K+1)个地点之一(K个存储桶和任意存储桶中的一个位置)。

因此有M=(K+1)^N个组合(此处为(2+1)^3=27 variants),范围0..M-1中的每个数字都对应于唯一组合(一对一映射)。

生成所有组合的简单方法是为范围0..M-1创建循环并在(K + 1) - 数字系统中表示循环计数器

for C = 0..M-1
   d = C
   for i = 0..N-1
     Bucket for i-th element = d %% (K+1)
     d = d / (K+1)

例如,可能会映射21 10 = 210 3 :第二个存储桶中的第一个元素,第一个存储桶中的第二个元素,以及第三个元素关闭:[ (2), (1) ]

16 10 = 121 3 [ (1,3), (2) ]