需要对数字组进行不同的排列

时间:2017-04-11 12:32:10

标签: mysql sql math permutation

我有从1到36的数字。我想要做的是将所有这些数字放入三个组中,并计算出各种组的各种排列。

每组必须包含12个数字,从1到36

根据排列,一个数字不能出现在多个组中

这是一个例子......

Permutation 1
Group 1: 1,2,3,4,5,6,7,8,9,10,11,12
Group 2: 13,14,15,16,17,18,19,20,21,22,23,24
Group 3: 25,26,27,28,29,30,31,32,33,34,35,36

Permutation 2
Group 1: 1,2,3,4,5,6,7,8,9,10,11,13
Group 2: 12,14,15,16,17,18,19,20,21,22,23,24
Group 3: 25,26,27,28,29,30,31,32,33,34,35,36

Permutation 3
Group 1: 1,2,3,4,5,6,7,8,9,10,11,14
Group 2: 12,11,15,16,17,18,19,20,21,22,23,24
Group 3: 25,26,27,28,29,30,31,32,33,34,35,36

这是三个例子,我预计会有数百万/十亿美元

1 个答案:

答案 0 :(得分:1)

下面的分析假设群组的顺序很重要 - 也就是说,如果数字是1,2,3,则分组[{1},{2},{3}]与分组[{3]不同},{2},{1}](实际上,从这组数字中取出时有六个不同的分组)。

在您的情况下,我们如何进行?好吧,我们必须先选择第一组。有36种选择12种方法,或者(36!)/ [(12!)(24!)] = 1,251,677,700种方式。然后我们必须选择第二组。有24种选择12种方法,或者(24!)/ [(12!)(12!)] = 2,704,156种方式。由于第二种选择已经以第一种方式为条件,我们可以通过乘以数字得到三组的总方式;从36个池中选择三个相同的12个组的方法总数为3,384,731,762,521,200。如果你使用8位字节表示数字,那么存储每个列表至少需要~3个五十亿字节(好吧,我猜的是列表的大小,这将是36个字节,所以更像是~108五字节)。这是一个很多数据,需要一些时间来生成,并且不需要存储少量磁盘空间,因此请注意这一点。

实际实现这一点并不是那么可怕。但是,如果可能的话,我认为你在SQL中实现这一点会有不适当的困难。纯SQL没有返回超过n ^ 2个条目的操作(对于简单的交叉连接),因此获得如此大量的结果将需要大量的连接。此外,由于纯SQL无法进行一般递归,因此无法对通用程序进行概括,因此不会对我进行概括,因此无法进行可变数量的连接。

您可以使用过程语言生成分组,然后将分组写入数据库。我不知道这是不是你想要的。

n = 36

group1[1...12] = []
group2[1...12] = []
group3[1...12] = []

function Choose(input[1...n], m, minIndex, group)

    if minIndex + m > n + 1 then
        return

    if m = 0 then

        if group = group1 then
            Choose(input[1...n], 12, 1, group2)

        else if group = group2 then
            group3[1...12] = input[1...12]
            print group1, group2, group3

    for i = i to n do

        group[12 - m + 1] = input[i]
        Choose(input[1 ... i - 1].input[i + 1 ... n], m - 1, i, group)

当你像Choose([1...36], 12, 1, group1)那样调用它时,它会填充group1,其中包含长度为12的所有可能的有序子序列。此时,m = 0且group = group1,因此调用Choose([?], 12, 1, group2)为make(对于group1的每个可能的选择,因此?)。这将为group2选择长度为12的所有剩余有序子序列,此时m = 0,现在group = group2。我们现在可以安全地为其余条目分配group3(在选择group1和group2之后,只有一种方法可以选择group3)。

我们只通过传播开始查看递归调用的索引(minIdx)来获取有序子序列。我们采用有序的子序列来避免得到同一组12项的排列(因为顺序在组内并不重要)。

循环中对Choose的每次递归调用都会移除input并移除一个元素:恰好是刚刚添加到所考虑的组中的元素。

我们检查minIndex + m > n + 1并提前停止递归,因为在这种情况下,我们在输入中跳过太多项目,以便能够用12个项目填充当前组(同时选择子序列到被命令)。

你会注意到我已经将12/36/3组的假设硬编码到程序的逻辑中。这样做是为了简洁和清晰,不是因为您无法在输入大小N和要形成的组k的数量中对其进行参数化。为此,您需要创建一个组数组(每组大小为N / k的k个组),然后使用N / k而不是12来调用Choose并使用select / switch case语句来代替if / then / else确定是再次Choose还是打印。但这些细节可以留作练习。