代码之家  ›  专栏  ›  技术社区  ›  agibson007

在Swift中将CGFloat数组分解为n个近似相等的子数组,保持顺序

  •  0
  • agibson007  · 技术社区  · 4 年前

    我有一组浮点值,我想把它们分成两组,每组的大小最多相差一个元素。此外,两组之间的值和差应该很小。可选地,如果元素数量为奇数且总和不相等,则较小的集合应具有较大的总和。

    这将是最佳解决方案,但我只需要一个关于子集大小约束的精确解决方案。严格来说,总和的差异不一定是最小的,但应该接近。此外,我更希望较小的集合(如果有的话)具有较大的总和。

    我意识到这可能与 partition problem ,但并不完全相同,也不那么严格。

    我目前的算法如下,但我想知道是否有改进的方法:

    arbitrarily divide the set into two sets of the same size (or 1 element size difference)
    do
      diffOfSums := sum1 - sum2
      foundBetter := false
      betterDiff := 0.0
    
      foreach pair of elements from set1 and set2 do
        if |diffOfSums - 2 * betterDiff| > |diffOfSums - 2 * (value1 - value2)| then
          foundBetter := true
          betterDiff := value1 - value2
        endif
      done
    
      if foundBetter then swap the found elements
    while foundBetter
    

    我对这种方法的问题是,我不确定实际的复杂性以及是否可以改进。它当然不能满足将较小的子集留给较大的总和的要求。

    是否有任何现有的算法恰好能实现我想要的目标?如果没有,你能给我建议一些方法来改进我的算法,或者弄清楚它可能已经对这个问题相当好了吗?

    0 回复  |  直到 9 年前
        1
  •  3
  •   Juan Lopes    9 年前

    很容易证明划分问题在多项式时间内简化为这个问题。

    想象一下,你想解决某个数组A的分区问题,但你只知道如何解决你的问题。你只需将数组长度加倍,用零填充即可。如果你能用你的算法解决它,那么你就解决了分区问题。这证明你的问题是NP难的。

    但你会发现,除非你限制浮点数的精度,否则你无法将这个问题简化为分区(即它不是NP完全)。在这种情况下,相同的算法将解决这两个问题。

    在一般情况下,你能做的最好的事情就是回溯。

        2
  •  2
  •   Gordon Linoff    9 年前

    我的建议是对值进行排序,然后考虑每对值(v1,v2),(v3,v4),将每对值中的一个元素放入一个分区中。

    这个想法是交替将值放入每个集合中,因此:

    s1 = {v1, v4, v5, v8, . . . }
    s2 = {v2, v3, v6, v7, . . . }
    

    如果元素数量为奇数,请将最后一个值放入最符合您条件的集合中。

    您对最小值的定义较为宽松,因此无需进行全面搜索。对于许多值的分布,上述方法应该非常有效。