基于组块权重的拆分数组

时间:2018-08-30 10:05:32

标签: python python-3.x algorithm approximation

我有一个2 <= n <= 100双打的数组:

A = [a1, a2, ... , an], ai > 0

和一个整数2 <= k <= min(n, 20)。我需要将A分成k个子数组:

B1 = [a1,     a2, ... , ap]
B2 = [ap+1, ap+2, ... , aq]

             ...

Bk = [aw+1, aw+2, ... , an] 

使得每个B中的总和几乎相等(很难给出严格的定义,这意味着-我对近似解感兴趣)。

示例:

Input: A = [1, 2, 1, 2, 1], k=2
Output: [[1, 2, 1], [2, 1]] or [[1, 2], [1, 2, 1]]

我尝试了一种概率方法:

  • 使用[1, 2, .., n]作为概率权重从A采样

  • 将样本切成分位数以找到合适的分区,

但这对生产来说还不够稳定。

tl; dr 这个question询问2个块的划分。我需要k-大块划分。

1 个答案:

答案 0 :(得分:3)

计算数组S的总和。每个大块总和应接近S / K

然后遍历数组,计算运行总和R。当R+A[i+1] - S/K大于S/K - R时,关闭当前块并制作R=0。继续下一块。

您还可以补偿累积误差(如果发生),将M块的总和与M * S / K进行比较

最后一种方法的快速编写的代码(未经彻底检查)

def chunks(lst, k):
    s = sum(lst)
    sk = s / k
    #sk = max(s / k, max(lst))
    #variant from user2052436 in comments  
    idx = 0
    chunkstart = 0
    r = 0
    res = []
    for m in range(1, k):
        for idx in range(chunkstart, len(lst)):
            km = k -m
            irest = len(lst)-idx
            if((km>=irest) or (2*r+lst[idx]>2*m*sk)) and (idx>chunkstart):
                res.append(lst[chunkstart:idx])
                chunkstart = idx
                break
            r += lst[idx]
    res.append(lst[idx:len(lst)])
    return res

print(chunks([3,1,5,2,8,3,2], 3))
print(chunks([1,1,1,100], 3))

>>>[[3, 1, 5], [2, 8], [3, 2]]
   [[1, 1], [1], [100]]