【问题标题】:Stuck with an interview Question... Partitioning of an Array被面试问题困住了......数组的分区
【发布时间】:2011-09-21 05:27:38
【问题描述】:

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

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

输入: 非负数 {s1, 的排列 S . . , sn} 和一个整数 k。

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

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

【问题讨论】:

  • 这不是 C++ 或 C 特定的——或者如果你想要一个解决方案,那么你必须只标记 C 或 C++。
  • “在所有范围内”是什么意思?
  • n 会 >= k 吗? @Tim:考虑到无论整数如何求和,所有值的最大总和都不会改变,他可能指的是每个分区中包含的值的总和。
  • minimize the maximum sum over all the ranges - 这是什么意思
  • @sehe,我认为这意味着对集合进行分区,以使最大和的分区之和最小。

标签: algorithm dynamic-programming


【解决方案1】:

让我们尝试使用动态规划来解决这个问题。

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

S = {s1 时,让d[ i ][ j] 是问题的解>, ..., si } 和 k = j。所以很容易看出:

  1. d[ 0 ][ j ] = 0 对于从 1k 的每个 j
  2. d[ i ][ 1 ] = sum(s1...si) 对于每个 i 来自1n
  3. d[ i ][ j ] = minfor t = 1 to i (max ( d[i - t][j - 1], sum(si - t + 1...si)) for i = 1 to n and j = 2 to k

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

  1. 当序列中没有元素时,很明显只能有一个区间(一个空区间)并且其元素之和为 0。这就是为什么 d[ 0 ][ j ] = 0 em> 表示从 1k 的所有 j
  2. 当只有一个区间时,很明显解是序列中所有元素的总和。所以 d[ i ][ 1 ] = sum(s1...si).
  3. 现在假设序列中有i个元素,区间数为j,我们可以假设最后一个区间为(si - t + 1...si) 其中 t 是不大于 i 的正整数,所以在这种情况下解决方案是 max ( d[i - t][j - 1], sum(si - t + 1...si), 但为我们希望解决方案是最小的,我们应该选择 t 这样来最小化它,所以我们将得到 minfor t = 1 to i (max ( d[i - t][j - 1], sum(si - t + 1...si)).

示例:

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;
}

【讨论】:

  • @Mihran - 看起来不错..你能为你的方法提供例子吗..它会更清楚......
  • 好的@AGeek我稍后会编辑我的答案,提供更清晰的解释。
  • 谢谢。兄弟。我正在等待您通过示例进行清晰的解释... :)
  • 纯数学解释......在你的 DP 解决方案中有点困惑......你能提供例子吗,我也很想用心学习 DP......这个数学是如何工作的......我想要继续讨论兄弟??
  • @MihranHovsepyan d[4][2] 不应该是 12 岁吗?实际上,您的程序返回 12。
【解决方案2】:

这个问题逐字逐句摘自 Steven Skiena 的书“The Algorithm Design Manual”。您可以在Google Books 上阅读详细讨论和他的解决方案。更好的是,buy the book

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-30
    • 2012-05-18
    • 1970-01-01
    • 2022-11-14
    • 2020-04-24
    • 2019-08-25
    相关资源
    最近更新 更多