按照它们的和的顺序生成k个元素子集的算法

时间:2013-02-28 00:54:56

标签: algorithm sorting dynamic-programming

如果我有一组未分类的n个整数(比如2^20个整数)并且想要生成每个k个元素的子集(其中k很小,说5)按其增加的顺序递增,最有效的方法是什么?

为什么我需要以这种方式生成这些子集是因为我想找到满足一定条件的最小和的k元素子集,因此我将在每个k-上应用条件元素子集生成。

此外,算法的复杂性是什么?

这里有一个类似的问题:Algorithm to get every possible subset of a list, in order of their product, without building and sorting the entire list (i.e Generators)关于按产品顺序生成子集,但由于集n

的大小非常大,因此无法满足我的需求

我打算在Mathematica中实现该算法,但也可以用C ++或Python来实现。

5 个答案:

答案 0 :(得分:1)

你的意思是20个整数,还是2 ^ 20?如果它真的是2 ^ 20,那么在找到满足条件的子集之前,您可能需要经历大量的(2^20 choose 5)子集。在现代的100k MIPS CPU上,假设只有1条指令可以计算一组并评估该条件,那么整个集合仍然需要3 quadrillion years。所以,如果你甚至需要经历一小部分,那就不会在你的一生中完成。

即使整数的数量较小,这似乎也是解决这个问题的一种相当强大的方法。我猜想你可能能够将你的条件表达为mixed integer program中的约束,在这种情况下,解决以下问题可能是获得解决方案比蛮力枚举更快的方法。假设你的整数是w_i,我从1到N:

min sum(i) w_i*x_i
    x_i binary
    sum over x_i = k
subject to (some constraints on w_i*x_i)

如果事实证明你的MIP的linear programming relaxation很紧,那么你很幸运并且有一种非常有效的方法来解决问题,即使是2 ^ 20个整数(例如:{{3}此外,您可以使用max-flow/min-cut problem的方法来查找解决方案,因为您可能有非常多的值无法同时解决。

如果您更多地了解您感兴趣的约束,我或其他人可能会为您提出一个更具体的解决方案,而不涉及强力枚举。

答案 1 :(得分:1)

即使只有千分之一的k大小的装置符合你的条件,那仍然是太多的组合来测试。我相信运行时使用nCk(n选择k)进行缩放,其中n是未排序列表的大小。 Andrew Mao的答案与这个价值有关。 10 ^ 28/1000仍然是10 ^ 25。即使每秒1000次测试,这仍然是10 ^ 22秒。 = 10 ^ 14年。

如果您被允许,我认为您需要从大型集合中删除重复的数字。删除的每个副本都会大大减少您需要执行的评估次数。对列表进行排序,然后杀死欺骗。

另外,你在寻找最好的答案吗?谁来验证答案,需要多长时间?我建议实施遗传算法并在一夜之间运行一堆实例(只要你有时间)。这将产生一个非常好的答案,比宇宙的持续时间短得多。

答案 2 :(得分:1)

如果小子集(称为P)的所需属性相当普遍,则概率方法可能效果很好:

  1. n个整数进行排序(对于数百万个整数,即10个到100个MB的ram,这应该不是问题),并将k-1加到最小值。将此总数称为offset
  2. 生成随机k - 子集(例如,通过抽样k随机数,mod n)并检查P - ness。
  3. 在匹配项上,记下子集的总和。从中减去offset以查找任何k的最大元素的上限 - 等效总和的子集。
  4. n整数集合限制为小于或等于此范围的整数。
  5. 重复(转到2),直到在一些固定的迭代次数内找不到匹配项。
  6. 请注意,初始排序为O(n log n)。步骤4中隐含的二进制搜索是O(log n)

    显然,如果P如此罕见以至于随机投篮不太可能得到一场比赛,这对你没有好处。

答案 3 :(得分:0)

这是一种近似的方式来做你正在说的话。

首先,对列表进行排序。然后,考虑一些长度为5的索引向量v,对应于排序列表中的位置,其中最大索引是某个数字m,还有一些其他索引向量v',有些最大索引m' > m。所有此类向量v'的最小总和始终大于所有向量v的最小总和。

所以,这里是你如何以近似增加的总和循环元素:

sort arr

for i = 1 to N
   for v = 5-element subsets of (1, ..., i)
     set = arr{v}
     if condition(set) is satisfied
       break_loop = true
       compute sum(set), keep set if it is the best so far
   break if break_loop

基本上,这意味着如果您在(1, ..., n+1)中找到令人满意的作业,则不再需要检查(1, ..., n)的5元素组合,因为任何令人满意的最大索引n+1作业会有更多的金额,你可以在那套之后停下来。但是,没有简单的方法来循环(1, ..., n)的5个组合,同时保证总和总是在增加,但至少你可以在找到满意的集合n后停止检查。

答案 4 :(得分:0)

这看起来是map-reduce(http://en.wikipedia.org/wiki/MapReduce)的完美候选者。如果您知道以任何方式对它们进行巧妙的划分,以便在每个节点中传递候选者同样存在,那么您可能会获得很高的吞吐量。

可能不需要完全排序,因为地图阶段可以处理它。然后,每个节点可以针对k元组验证条件,并将结果输出到稍后可以聚合/缩减的文件中。

如果您知道发生的可能性并且不需要所有结果,请尝试查看概率算法以收敛答案。