如何计算将数组中所有n个数转换为m的最小成本?

时间:2016-06-05 07:27:55

标签: c++ algorithm

我获得了以下任务:

  

给定A(i)形式的N个整数,其中1≤i≤N,得到每个数   A(i)中的N个数等于M.要将数字A(i)转换为M,它   将花费| M-Ai |单位。找出转换所有N的最低成本   数字到M,所以你应该选择最好的M来获得最低成本。

     

假设:

1 <= N <= 10^5

1 <= A(i) <= 10^9

我的方法是计算所有数字的总和并找到avg = sum / n,然后将每个数字减去avg以获得最低费用。

但是在许多测试用例中都失败了。我怎样才能找到最佳解决方案?

2 个答案:

答案 0 :(得分:4)

你应该取数字的中位数(如果列表长度均匀,则取两个数字中间最接近的数字),而不是均值。

平均值未能最小化的示例是:[1,2,3,4,100]。平均值是110/5 = 22,总成本是21 + 20 + 19 + 18 + 78 = 156.选择中位数(3)给出总成本:2 + 1 + 0 + 1 + 97 = 101。

中位数位于列表中两个项目之间的示例是[1,2,3,4,5,100]。这里的中位数是3.5,使用M = 3或M = 4都可以。对于M = 3,总成本为2 + 1 + 0 + 1 + 2 + 97 = 103.对于M = 4,总成本为3 + 2 + 1 + 0 + 1 + 96 = 103。

可以在Mathematics SE上找到正确的正式证明,尽管您可以通过注意如果您在一个方向上轻微推动M(但不是超过其中一个数据点)来说服您自己的结果 - 例如,让我们说它是正方向,总成本增加delta乘以M左边的点数减去delta乘以点的数量当左边和右边的点数在数量上相等时,M的权利被最小化,否则你可以以一种方式向其移动少量以减少总成本。

答案 1 :(得分:0)

@PaulHankin已经提供了一个完美的答案。无论如何,在考虑问题时,我并没有想到中位数是解决方案。但即使您不了解中位数,也可以提出编程解决方案。

我在他最后一个答案的最后一段中与@PaulHankin做了类似的观察。这让我意识到,为了找到m,我必须迭代地消除异常值。所以我编写了一个程序,首先对输入数组(向量)A进行排序,然后分析最小值和最大值。

这个想法是将最小值移向第二个最小值,将最大值移向第二个最大值。您始终移动最小值或最大值,具体取决于您是否具有最小值而不是最大值。如果所有数组项最终都是相同的值,那么您找到了m

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

int getMinCount(vector<int>& A);
int getMaxCount(vector<int>& A);

int main()
{
    // Example as given by @PaulHankin
    vector<int> A;
    A.push_back(1);
    A.push_back(2);
    A.push_back(3);
    A.push_back(4);
    A.push_back(100);

    sort(A.begin(), A.end());

    int minCount = getMinCount(A);
    int maxCount = getMaxCount(A);

    while (minCount != A.size() && maxCount != A.size())
    {
        if(minCount <= maxCount)
        {
            for(int i = 0; i < minCount; i++)
                A[i] = A[minCount];

            // Recalculate the count of the minium value, because we changed the minimum.
            minCount = getMinCount(A);
        }
        else
        {
            for(int i = 0; i < maxCount; i++)
                A[A.size() - 1 - i] = A[A.size() - 1 - maxCount];

            // Recalculate the count of the maximum value, because we changed the maximum.
            maxCount = getMaxCount(A);
        }
    }

    // Print out the one and only remaining value, which is m.
    cout << A[0] << endl;
    return 0;
}

int getMinCount(vector<int>& A)
{
    // Count how often the minimum value exists.
    int minCount = 1;
    int pos = 1;
    while (pos < A.size() && A[pos++] == A[0])
        minCount++;

    return minCount;
}

int getMaxCount(vector<int>& A)
{
    // Count how often the maximum value exists.
    int maxCount = 1;
    int pos = A.size() - 2;
    while (pos >= 0 && A[pos--] == A[A.size() - 1])
        maxCount++;

    return maxCount;
}

如果您考虑算法,那么您将得出结论,它实际上计算了数组A中值的中值。作为示例输入,我采用了@PaulHankin给出的第一个示例。正如所料,代码为它提供了正确的结果(3)。

我希望我的方法可以帮助您了解如何解决此类问题,即使您不知道正确的解决方案。例如,当你参加面试时,这尤其有用。