【问题标题】:Divide an array into k or less subparts to minimize the maximum sum of each part将一个数组划分为 k 个或更少的子部分,以最小化每个部分的最大和
【发布时间】:2014-08-17 19:04:47
【问题描述】:

我需要将一个数组分成 k 个或更少的子部分,以最小化每个部分的最大总和。

例如一个数组有元素:5,10,21,20

如果k=2,则数组可以分为2个子数组:{5,10,21}{20}。 我们必须返回子数组的最大和(上例中为36)。

k>=4 时,答案将是数组中最大的元素。

另外,数组元素的选择顺序不能改变,所以我们不能只对数组进行排序就继续。

【问题讨论】:

  • 数组是如何划分的?为什么不是 {5, 10} 和 {21,21}?哪种编程语言?
  • 如果我们像{5,10}和{20,21}这样划分它,子数组的最大和变为41。但这必须最小化。 C、C++ 或 Java 都可以。我只是在寻找算法。

标签: arrays dynamic-programming


【解决方案1】:

这显然是一个动态规划问题。

数组除法的问题,等于把k-1个除法放入数组中。

让你的数组被称为 A。 并设 m[i,k] 是 A 的元素的最佳划分,直到第 i 个元素有 k 个划分

m[0,*] = 0
m[i,0] = a[i] 
m[i,j] = min{m[i-1,j] + a[i], max{m[i-1,j-1], a[i]}}

m[i,j] 是在点 i 处分割数组与不分割之间的最小值。

你计算一下就能找到答案

m[length(A), k-1]

您可以从那里回溯部门。

【讨论】:

    【解决方案2】:

    如果你想要一个足够好的解决方案,你可以使用贪婪的解决方案:

    def minmax(lst, k):
        lst = sorted(lst, reverse=True)  # biggest numbers first is usually better
        subs = [[] for _ in xrange(k)]   # create the lists for the subarrays
    
        while lst:
            subs[0].append(lst.pop(0))         # append to the one with lowest sum
            subs.sort(key=sum)                 # sort by sum (lowest first)
            print subs                   # print the subarrays while creating them
    
        return sum(subs[-1])    # we have sorted by sums, last has the biggest sum
    

    这并不能保证产生最佳结果,但效果很好。

    k = 2

    这是你的例子:

    print 'result is %d' % minmax([5, 10, 21, 20], 2)
    

    输出

    [[], [21]]
    [[20], [21]]
    [[21], [20, 10]]
    [[21, 5], [20, 10]]
    result is 30
    

    嗯,它找到了比你展示的更好的解决方案。

    k >= 4

    让我们试试k=4k=5

    >>> print 'result is %d' % minmax([5, 10, 21, 20], 4)
    [[], [], [], [21]]
    [[], [], [20], [21]]
    [[], [10], [20], [21]]
    [[5], [10], [20], [21]]
    result is 21
    
    >>> print 'result is %d' % minmax([5, 10, 21, 20], 5)
    [[], [], [], [], [21]]
    [[], [], [], [20], [21]]
    [[], [], [10], [20], [21]]
    [[], [5], [10], [20], [21]]
    result is 21
    

    你也可以在函数开头加上这段代码,当k >= len(lst)时直接返回lst的最大值:

    def minmax(lst, k):
        if k >= len(lst):
            return max(lst)
        ....
    

    最小制造跨度问题

    这类问题以Minimum Makespan Problem的名字而闻名,搜索它你会检索到很多关于保证产生最佳结果的算法的信息,但它们的解释太远了堆栈溢出答案很复杂,而贪婪的答案很有趣且有启发性。

    【讨论】:

    • 好吧,我没有提到一件事,数组元素出现的顺序不能改变。因此,我们不能只对数组进行排序并继续。对不起,我之前没有提到这一点,因为我认为我给出的例子很明显。我将把它附加到问题本身。
    【解决方案3】:

    一个更好的办法是在这里使用二分搜索:

    您可以通过使用简单的贪心算法来测试 m(desired maximum sum) 的候选值是否在 O(n) 中是好的:*只要尽可能长地取前缀不超过 m,如果关闭则截断,并且重新开始。如果这个过程在

    因此,您可以对 m [0,2^32 - 1] 的值进行二分搜索。

    复杂度:O(n*log(sum(array)))

    如果 sum(array) 与 n 相当,则该算法将在线性时间内运行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-28
      • 2017-02-02
      • 1970-01-01
      • 1970-01-01
      • 2012-09-05
      • 2020-04-20
      • 2014-09-20
      • 1970-01-01
      相关资源
      最近更新 更多