将数组划分为k个连续分区,以使最大分区的总和最小

use*_*989 2 c++ arrays algorithm dynamic-programming subset-sum

这里最大和子集是k个子集之一,它给出最大和,例如:arr = [10,5,3,7]和k =将arr划分为k个子集的2种可能方式是{10,[5,3,7]} ,{{10,5],[3,7},{[10,5,3],7}和{[10,5],[3,7}是最佳选择。编辑:它等效于 https://www.codechef.com/DI15R080/problems/MINMAXTF

v78*_*v78 6

这是一个二进制搜索样本空间的例子。

int min_max_sum(std::vector<int> & a, int K) {        

    int n = a.size();    
    long long high = 0, low = 0, mid = 0;

    for (int i = 0; i < n; ++i) {
        high += a[i];
        low = max(a[i], low);
    }

    while(low <= high) {
        mid = (low+high)/2;

        long long part_sum = 0;
        int parts = 1;
        for (int i = 0; i < n; ++i) {
            if (part_sum + a[i] > mid) {
                part_sum = 0;
                parts++;
            } else {
                part_sum += a[i];
            }
        }

        // if no. of parts in less than (or equal to) K then mid needs to (,or can) be more constrained by reducing upper limit
        if (parts <= K) {
            high = mid - 1;
        } else { 
            low = mid + 1;
        }
    }

    return mid;
}
Run Code Online (Sandbox Code Playgroud)

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

但是由于对数比线性好成指数级,所以这种复杂度非常好。

最坏情况复杂度:O(n log(INT_MAX * n))=O(32 n +n log(n))=O(n log(n))。


Tem*_*pux 5

假设您知道答案是x,这意味着最大子集的总和等于x。您可以通过贪婪算法O(n)验证此假设。(从左到右遍历该数组并选择项目,直到该子集的总和小于x为止)。现在,您可以二进制搜索在X和查找最小值X。该算法的复杂度为O(nlogn)

  • 当然。这样考虑:您有一些都具有* x *容量的袋子。您想将这些物品(从左到右)放在这些袋子中,并且希望减少袋子的数量。贪婪的方法将解决此问题。您可以轻松地查看当前行李袋是否有足够的容量容纳应放入的当前物品,否则可能会增加所需行李袋的数量。您可以将上述问题的贪婪部分简化为该袋子问题。 (3认同)

A. *_*rid 1

这可以使用动态规划来解决:

让我们首先定义DP[n,m]将子数组划分为多个部分的最佳解决C[1..n]方案m。其中每个部分至少有一个元素。

DP[n,1] = sum(C1:Cn)
DP[n,n] = max(C1:Cn)
DP[n,m] = min( sum(Ck:Cn) + DP[k-1,m-1] )
          where k goes from m to n
Run Code Online (Sandbox Code Playgroud)

解释:
DP[n,1] - 基本情况,当分区数量为 时,1只有一种方法 - 留下所有元素(从 1 到 n)。
DP[n,n]- 每当分区数量等于数组中剩余元素的数量时,只有一种合法的划分方法 - 每个元素位于不同的分区中,因此具有最大总和的分区是数组中的最大元素。
DP[n,m]- 这是主要的解决方案。我们不知道下一个分区将有多少个元素,因此我们需要检查所有选项并从中获取最小值。