递归地划分每个迭代分成两部分的列表,以获得最接近的总和

时间:2015-06-09 06:05:23

标签: algorithm binary-tree dynamic-programming approximation partition-problem

给出一个数字列表L = {a1,a2,a3,a4,...,aN}

问题是将这个 L 分成两部分,不仅仅是一次,而是递归,直到它变成原子。主要思想就像this post,但添加了递归的东西。

(已添加:6月9日) 例如,如果我们有L = {10,20,1,2} (已编辑:6月10日)< / em>解决方案可能首先将其除以{10,1,2}和{20},然后将前者划分为{1,2}和{10},继续{1,2}转到{ 1},{2}。现在L的所有成员现在原子不再被分割了。

分割后,它应该看起来像某种二叉树。

让我们说它看起来像这样......

  (a1 a2 a3 a4)
       /\
      /  \
     /    \
    /      \
 (a1 a2) (a3 a4)
   /\      /\
  /  \    /  \
(a1)(a2)(a3)(a4)

在每个节点处,相似度函数是

abs( sum(left_child) - sum(right_child) ) / sum(itself)

我想找一个&#34;优化&#34;根据&#34;求和&#34;划分列表(创建树)的方法此功能。请注意,在顶层,此值可能比较低的值具有更大的影响,因此应提供权重。

weight(level) * abs( sum(left_child) - sum(right_child) ) / sum(itself)

级别是二叉树中此节点的级别。

我认为可以使用动态编程来解决这个问题,时间复杂度为O(2 ^ N)。但是,这个解决方案对我来说似乎太慢了。有谁有更好的解决方案?

欢迎优化和近似。

提前谢谢。

1 个答案:

答案 0 :(得分:0)

O(n)时间复杂度但真正不准确的方法是:

def distance(a, b):
    return abs(a - b)

def balancedSlice(myList):

    total = sum(myList)
    a = 0        #a, b are the sum's of each slice
    b = total
    dist = distance(a, b) # current distance between slices
    for i in range (len(myList)):
        a += myList[i]
        b -= myList[i]
        if dist <= distance(a, b):
            return myList[:i],myList[i:] #list sliced "from 0 to before i" and "from i to end"
        dist = distance(a, b)

O(n log n)中另一个更准确但不完美的贪心算法:

def balancedSlice(myList):
    list1 = list()
    list2 = list()
    myList = list(myList) #skip if you can destroy the original list.
    myList.sort() # O(n log n)
    while myList:
        item = myList.pop()
        if sum(list1) <= sum(list2):
            list1.append(item)
        else:
            list2.append(item)
    return list1, list2

然而,正如here所述,这是一个NP问题,所以如果你的列表足够大并且你可以容忍不完美的结果,你应该坚持使用这种贪婪算法。