【问题标题】:How to find split where the split sums are close to each other?如何找到拆分总和彼此接近的拆分?
【发布时间】:2017-02-25 10:50:22
【问题描述】:

我有一个清单是

测试 = [10,20,30,40,50,60,70,80,90,100]

​并且我想通过所有可能的组合的拆分数 = 3 来找到拆分总和彼此接近的拆分,并选择总和差异最小的拆分。

【问题讨论】:

  • 对此一无所知。请使用您在此处提供的测试用例阐明并给出所需的输出或逐步示例。
  • 你的问题不清楚。我认为您想将列表分成 3 个部分,每个部分的总和大致相同,例如 [[10,20,30,40,50], [60,70,80], [90,100]]。那是对的吗?您可以更改项目的顺序吗?如果是这样,[[10,20,30,40,80], [50,60,70], [90,100]] 将是一个可能的解决方案。
  • 你有没有尝试过的示例代码?
  • 是的。这是正确的。并且不允许更改顺序(:
  • SO 不是代码编写服务。如果您希望人们提供帮助,请展示您已完成的工作。

标签: python python-2.7 python-3.x recursion split


【解决方案1】:

第一个脚本使用双 for 循环将输入列表拆分为所有可能的三组列表。对于每个三元组,它计算三元组中每个列表的总和,然后创建一个名为 diffs 的排序列表,其中包含这些总和的绝对差。它将一个由diffs 和后跟三元组组成的元组保存到一个名为all_splits 的列表中。最后,它对all_splits 进行排序,因为all_splits 中的每个项目都以diffs 开头,所以保存的元组按照它们的diffs 从低到高的顺序进行排序。

def split_list_test(lst):
    all_splits = []
    for i in range(1, len(lst) - 1):
        for j in range(i + 1, len(lst)):
            splits = [lst[:i], lst[i:j], lst[j:]]
            a, b, c = map(sum, splits)
            diffs = sorted((abs(c-a), abs(c-b), abs(b-a)), reverse=True)
            all_splits.append((diffs, splits))
    all_splits.sort()
    return all_splits

test = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]

for row in split_list_test(test):
    print(row)

输出

([60, 40, 20], [[10, 20, 30, 40, 50], [60, 70, 80], [90, 100]])
([60, 40, 20], [[10, 20, 30, 40, 50, 60], [70, 80], [90, 100]])
([140, 110, 30], [[10, 20, 30, 40, 50, 60], [70, 80, 90], [100]])
([140, 120, 20], [[10, 20, 30, 40, 50], [60, 70], [80, 90, 100]])
([160, 90, 70], [[10, 20, 30, 40], [50, 60, 70, 80], [90, 100]])
([170, 90, 80], [[10, 20, 30, 40], [50, 60, 70], [80, 90, 100]])
([180, 110, 70], [[10, 20, 30, 40, 50, 60, 70], [80, 90], [100]])
([200, 110, 90], [[10, 20, 30, 40, 50, 60, 70], [80], [90, 100]])
([200, 140, 60], [[10, 20, 30, 40, 50, 60], [70], [80, 90, 100]])
([200, 150, 50], [[10, 20, 30, 40, 50], [60, 70, 80, 90], [100]])
([210, 160, 50], [[10, 20, 30], [40, 50, 60, 70], [80, 90, 100]])
([240, 130, 110], [[10, 20, 30], [40, 50, 60, 70, 80], [90, 100]])
([240, 220, 20], [[10, 20], [30, 40, 50, 60, 70], [80, 90, 100]])
([240, 230, 10], [[10, 20, 30, 40], [50, 60], [70, 80, 90, 100]])
([250, 250, 0], [[10, 20, 30, 40], [50, 60, 70, 80, 90], [100]])
([260, 260, 0], [[10], [20, 30, 40, 50, 60, 70], [80, 90, 100]])
([270, 260, 10], [[10, 20, 30, 40, 50, 60, 70, 80], [90], [100]])
([280, 190, 90], [[10, 20, 30], [40, 50, 60], [70, 80, 90, 100]])
([280, 190, 90], [[10, 20, 30, 40, 50], [60], [70, 80, 90, 100]])
([300, 160, 140], [[10, 20], [30, 40, 50, 60, 70, 80], [90, 100]])
([310, 160, 150], [[10, 20], [30, 40, 50, 60], [70, 80, 90, 100]])
([330, 190, 140], [[10], [20, 30, 40, 50, 60], [70, 80, 90, 100]])
([330, 290, 40], [[10, 20, 30], [40, 50, 60, 70, 80, 90], [100]])
([340, 180, 160], [[10], [20, 30, 40, 50, 60, 70, 80], [90, 100]])
([340, 310, 30], [[10, 20, 30], [40, 50], [60, 70, 80, 90, 100]])
([350, 300, 50], [[10, 20, 30, 40], [50], [60, 70, 80, 90, 100]])
([370, 280, 90], [[10, 20], [30, 40, 50], [60, 70, 80, 90, 100]])
([390, 260, 130], [[10], [20, 30, 40, 50], [60, 70, 80, 90, 100]])
([390, 320, 70], [[10, 20], [30, 40, 50, 60, 70, 80, 90], [100]])
([410, 390, 20], [[10, 20, 30], [40], [50, 60, 70, 80, 90, 100]])
([420, 380, 40], [[10, 20], [30, 40], [50, 60, 70, 80, 90, 100]])
([430, 340, 90], [[10], [20, 30, 40, 50, 60, 70, 80, 90], [100]])
([440, 360, 80], [[10], [20, 30, 40], [50, 60, 70, 80, 90, 100]])
([460, 460, 0], [[10, 20], [30], [40, 50, 60, 70, 80, 90, 100]])
([480, 440, 40], [[10], [20, 30], [40, 50, 60, 70, 80, 90, 100]])
([510, 500, 10], [[10], [20], [30, 40, 50, 60, 70, 80, 90, 100]])

下一个脚本更紧凑一些,它只返回一个解决方案。它使用不同的规则来决定最小拆分。如果(a, b, c) 是三元组中列表的总和,从最低到最高排序,那么这些总和的绝对差是c-ac-bb-a。差值之和为c-a + c-b + b-a,等于2*(c-a),因此我们可以通过查找最小值为c-a 的拆分来找到最小拆分(使用此规则)。

def keyfunc(seq):
    sums = sorted(sum(u) for u in seq)
    return sums[2] - sums[0]

def split_list(lst):
    gen = ([lst[:i], lst[i:j], lst[j:]]
        for i in range(1, len(lst) - 1)
            for j in range(i + 1, len(lst)))
    return min(gen, key=keyfunc)

test = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
print(split_list(test))

输出

[[10, 20, 30, 40, 50], [60, 70, 80], [90, 100]]

如您所见,对于这个test 列表,此版本提供的解决方案与上面找到的最小解决方案之一相同。

【讨论】:

    猜你喜欢
    • 2011-05-27
    • 2017-05-04
    • 2013-01-14
    • 2013-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-22
    相关资源
    最近更新 更多