【问题标题】:Arrange n items in k nonempty groups such that the difference between the minimum element and the maximum element of each group is minimized将 n 个项目排列在 k 个非空组中,使得每个组的最小元素和最大元素之间的差异最小化
【发布时间】:2017-03-04 12:38:38
【问题描述】:

给定 N 个值为 x[1], ..., x[n] 和整数 K 的项目,找到一个线性时间算法来将这些 N 个项目排列在 K 个非空组,使得每个组中的范围(每个组中的最小和最大元素值/键之间的差异)最小化,因此范围的总和最小。

例如给定N=4K=2 和元素1 1 4 3,对于组(1,1)(4,3),最小范围是1

【问题讨论】:

  • 参数范围。
  • 如果对它们进行排序会发生什么?如果 n%k 不为 0 会怎样?一个组可以小于 k 吗?
  • 组不能为空。这意味着它将有 >=1 个元素
  • n的最大范围是多少?
  • 你可以最小化一件事。 “最小化每个组的差异”是没有意义的。差异 3 和 4 的两组或差异 2 和 5 的两组哪个更好?

标签: algorithm dynamic-programming greedy


【解决方案1】:

您可以对答案进行二分搜索。
假设最佳答案是 x。现在您应该验证我们是否可以将项目分组到 k 个组中,其中组项之间的最大差异最多为 x。这可以在 O(n) [对数组排序后] 中完成。遍历排序后的数组并选择连续的项目,直到您为该组选择的最小数量与您选择的最大数量之间的差异不超过 x。之后,您应该初始化一个新组并重复此过程。最后数一数你做了多少组。如果组的数量超过 k,我们可以得出结论,我们不能将 k 组中的项目分组,而 x 是答案。所以我们应该增加x。通过对x的二分查找,我们可以找到最小的x

整体复杂度为O(NlogN)

这是 C++ 中的示例实现

#include <algorithm>
#include <iostream>

using namespace std;

int main()
{
    int n = 4, k = 2;
    std::vector<int> v = {1, 1, 4, 3};
    sort(v.begin(), v.end());

    int low = 0, high = *max_element(v.begin(), v.end());

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

        int groups = 0;
        int left = 0;
        while (left < v.size()){
            int right = left;
            while( right < v.size() && v[right] - v[left] <= x ){
                ++right;
            }
            ++groups;
            left = right;
        }
        // printf("x:%d groups:%d\n", x, groups );
        if (groups > k)
        {
            low = x + 1;
        } else {
            high = x;
        }
    }

    cout << "result is " << low << endl;

}

【讨论】:

    【解决方案2】:

    好的,我假设我们希望最小化所有组的差异总和。

    1. 让我们对数字进行排序。有一个最优答案,每组是排序数组中的一个连续片段(证明:让 A1

    2. 设 a[l], a[l + 1], ..., a[r] 是一个群。费用为a[r] - a[l] = (a[r] - a[r - 1]) + (a[r - 1] - a[r - 2]) + ... + (a[l + 1] - a[l])。它引导我们得出一个关键见解:k 组是k - 1 差距,答案是a[n - 1] - a[0] - sum of gaps。因此,我们只需要最大化差距。

    3. 这是一个最终的解决方案:

      • 对数组进行排序
      • 计算相邻数字之间的差异
      • k - 1 的最大差异。这正是小组分裂的地方。
      • 我们可以在线性时间内找到k-1th 最大的元素(或者如果我们对O(N log N) 时间没问题,我们可以对它们进行排序)。就是这样。

    这是一个例子:

    x = [1, 1, 4, 3], k = 2
    排序:[1, 1, 3, 4]
    差异:[0, 2, 1]
    k - 1 = 1 最大的差距:它是2。因此这些组是[1, 1][3, 4]

    一个稍微做作的:
    x = [8, 2, 0, 3], k = 3
    排序:[0, 2, 3, 8]
    差异:[2, 1, 5]
    k - 1 = 2 最大的差距:它们是2 和5。因此,这些组是[0], [2, 3], [8],总成本为1。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-09
      • 1970-01-01
      • 1970-01-01
      • 2015-12-02
      • 2017-01-03
      • 1970-01-01
      • 2016-12-28
      • 2019-08-28
      相关资源
      最近更新 更多