坚持面试问题......数组的分区

AGe*_*eek 15 algorithm dynamic-programming

我在互联网上发现了以下问题,并想知道我将如何解决它:

问题:没有重新排列的整数分区

输入:非负数的排列S {s 1,... ..,s n }和整数k.

输出:将分区S分成k个或更少的范围,以最小化所有k个或更少范围的总和的最大值,而无需重新排序任何数字.*

请帮忙,看起来像有趣的问题......我实际上花了很多时间,但没有看到任何解决方案..

Mih*_*yan 21

让我们尝试使用动态编程解决问题.

注意:如果k> n,我们只能使用n个区间.

S = { s 1,...,s i }和k = j时,考虑d [i] [j]是问题的解.所以很容易看出:

  1. 对于从1k的每个j,d [0] [j] = 0
  2. d [i] [1] =1n的每个i的和(s 1 ... s i)
  3. d [i] [j] = min 为t = 1到i(max(d [i - t] [j - 1],sum(s i - t + 1 ... s i))i = 1到n和j = 2到k

现在让我们看看为什么这样有效:

  1. 当序列中没有元素时,很明显只有一个区间可以(空的)和它的元素之和为0.这就是为什么d [0] [j] = 0对于从1k的所有j.
  2. 当只有一个区间时,很明显解是所有序列元素的总和.所以d [i] [1] = sum(s 1 ... s i).
  3. 现在让我们考虑序列中有i个元素,区间数是j,我们可以假设最后一个区间是(s i - t + 1 ... s i)其中t是不大于i的正整数,所以在那里情况下的解决方案是最大(d [它] [j - 1],和(š 它+ 1内容S ),但因为我们希望该溶液是最小的,我们应该选择等,以尽量减少,所以我们将得到min 为t = 1到i(max(d [i - t] [j - 1],sum(s i - t + 1 ... s i)).

例:

S =(5,4,1,12),k = 2

d [0] [1] = 0,d [0] [2] = 0

d [1] [1] = 5,d [1] [2] = 5

d [2] [1] = 9,d [2] [2] = 5

d [3] [1] = 10,d [3] [2] = 5

d [4] [1] = 22,d [4] [2] = 12

码:

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;

int main ()
{
    int n;
    const int INF = 2 * 1000 * 1000 * 1000;
    cin >> n;
    vector<int> s(n + 1);
    for(int i = 1; i <= n; ++i)
        cin >> s[i];
    vector<int> first_sum(n + 1, 0);
    for(int i = 1; i <= n; ++i)
        first_sum[i] = first_sum[i - 1] + s[i];
    int k;
    cin >> k;
    vector<vector<int> > d(n + 1);
    for(int i = 0; i <= n; ++i)
        d[i].resize(k + 1);
    //point 1
    for(int j = 0; j <= k; ++j)
        d[0][j] = 0;
    //point 2
    for(int i = 1; i <= n; ++i)
        d[i][1] = d[i - 1][1] + s[i]; //sum of integers from s[1] to s[i]
    //point 3
    for(int i = 1; i <= n; ++i)
        for(int j = 2; j <= k; ++j)
        {
            d[i][j] = INF;
            for(int t = 1; t <= i; ++t)
                d[i][j] = min(d[i][j], max(d[i - t][j - 1], first_sum[i] - first_sum[i - t]));
        }


    cout << d[n][k] << endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)


NPE*_*NPE 8

这个问题是从Steven Skiena的书" 算法设计手册 "中逐字记录下来的.您可以在Google图书上阅读详细讨论及其解决方案.更好的是,买这本书.