【问题标题】:Recursively divide a list that each iteration divides into two parts to get the closest sum overall递归地划分一个列表,每次迭代分为两部分以获得最接近的总和
【发布时间】:2015-08-23 19:17:51
【问题描述】:

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

问题是将这个 L 分成两部分,不只是一次,而是递归地,直到它变成原子的。主要思想类似于this post,但添加了递归。

(添加:6 月 9 日) 例如,如果我们有 L = {10, 20, 1, 2} (编辑:6 月 10 日) 解决办法可能是,先把它分成 {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)

我想根据这个函数的“求和”找到一种“优化”的方式来划分列表(创建树)。请注意,在顶层,这个值可能会产生更大的影响比较低的,所以应该提供权重。

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

let level 是这个节点在二叉树中的级别。

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

也欢迎优化和近似。

提前谢谢你。

【问题讨论】:

  • 检查我的答案,我更新了它以使其适合您的问题实例。
  • @AshkanKzme 我确实检查了它,但我发现它没有达到我的目的,因为我想最小化相似函数的总和(如上所述)..您提出的解决方案将针对每个节点进行优化,但不是针对整个树..顺便说一句。非常感谢您的快速回复
  • @AshkanKzme 你删除了你的答案吗?还是我又做错了什么?当我刷新并没有发现任何东西时,我感到震惊..
  • 我删除了答案,因为它没有为您的问题提供正确的解决方案。而且我有点认为你不能得到更好的 O(2^N) 运行时间与你的权重约束,这使得问题非常难以解决!
  • 绝对有必要递归吗?我相信有很多方法可以在 O(n) 时间内获得您想要的结果,而无需使用递归

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


【解决方案1】:

一个 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 问题,所以如果您的列表足够大并且您可以容忍不完美的结果,您应该坚持使用这种贪心算法。

【讨论】:

  • 我现在知道了.. 问题是列表中元素的顺序并不重要.. 我可以将它们打乱,应该得到相同的结果。还有一件事..您还必须保证根据我提供的功能将“整体”距离最小化..抱歉我的解释不佳。
  • 所以基本上你有一堆物品,想把它们装在 2 个袋子里(列表、套装等),这样它们就尽可能平衡了,对吧?
  • 不只是 2 个袋子,因为每个袋子可能有自己的子袋子,请参见上面的二叉树:D
猜你喜欢
  • 2011-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-25
  • 2014-06-22
  • 2018-04-05
相关资源
最近更新 更多