原文地址:Chocolate Distribution Problem
已知一个有n个整数的数组,数组中的每个值表示的是一个包裹中巧克力的数量。每个包裹都有一个表示巧克力数量的变量。这里有m个学生,按下面的规定把巧克力包裹分发出去:
- 每个学生都得到一个包裹;
- 给到学生的巧克力包裹含有的最大巧克力数目与最小巧克力数目的的差为最小。
例子:
输入: arr[] = {7, 3, 2, 4, 9, 12, 56}
m = 3
输出: 最小差是2
我们有七个巧克力包裹,并且需要选出3个给学生,如果我们选择2,3,4的话,那么我们就得到了最大包裹与最小包裹的最小差。
输入: arr[] = {3, 4, 1, 9, 56, 7, 9, 12}
m = 5
输出: 最小差是6
例如集合3,4,7,9,9,那么输出为9-3 = 6
输入: arr[] = {12, 4, 7, 9, 2, 23, 25, 41, 30, 40, 28, 42, 30, 44, 48, 43, 50}
m = 7
输出: 10
我们得选出7个包裹。选择40,41,42,44,48,43和50得到最大值和最小值的差。
一个简单的方案就是生成所有大小为m的arr[0..n-1]的子集。对于每个子集,然后找出其中的最大值与最小值的差,最后返回最小的差。
另一个有效的方法就是基于观察来最小化差距,我们必须从有序的包裹中选择连续的元素,我们首先对arr[0..n-1]进行排序,然后找到大小为m的子集的最后一个元素与第一个元素的差的最小值。
// C++ program to solve chocolate distribution
// problem
#include<bits/stdc++.h>
using namespace std;
// arr[0..n-1] represents sizes of packets m is number of students.
// Returns minimum difference between maximum and minimum values of distribution.
int findMinDiff(int arr[], int n, int m)
{
// if there are no chocolates or number
// of students is 0
if (m==0 || n==0)
return 0;
// Sort the given packets
sort(arr, arr+n);
// Number of students cannot be more than
// number of packets
if (n < m)
return -1;
// Largest number of chocolates
int min_diff = INT_MAX;
// Find the subarray of size m such that difference between last (maximum in case
// of sorted) and first (minimum in case of sorted) elements of subarray is minimum.
int first = 0, last = 0;
for (int i=0; i+m-1<n; i++)
{
int diff = arr[i+m-1] - arr[i];
if (diff < min_diff)
{
min_diff = diff;
first = i;
last = i + m - 1;
}
}
return (arr[last] - arr[first]);
}
int main()
{
int arr[] = {12, 4, 7, 9, 2, 23, 25, 41,
30, 40, 28, 42, 30, 44, 48,
43, 50};
int m = 7; // Number of students
int n = sizeof(arr)/sizeof(arr[0]);
cout << "Minimum difference is "
<< findMinDiff(arr, n, m);
return 0;
}
输出:
Minimum difference is 10
时间复杂度是:O(nLogn),因为我们在子数组查询前做个了排序。