Vito's Family

2013-05-07 Robert Zhang 更多博文 » 博客 » GitHub »

原文链接 http://huiming.io/2013/05/07/vitos-family.html
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。


分析:该题等价于“寻找一个正整数A,使得在一个给定的正整数数列中的每一个数与A的差的绝对值之和最小”。显然A应当不小于该数列的最小值,不大于该数列的最大值。乍看上去,似乎平均数是一个比较合理的解,但考虑一个例子“1 30000 30000”,其平均数约20000,此时的和约为40000,但如果A取30000,其和约为30000,显然取平均数是错误的。经过一番尝试,似乎中位数是一个更合理的解。<!--more-->但如何证明?这到颇费思量,可参考

中位数性质的证明。得到证明之后,解题便相当容易了。另外值得商榷的是:书中本题的难度系数很低,但如果不了解中位数的这个性质,解题还是相当头疼的。因此笔者以为这不是一道好题目。

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>

using namespace std;

inline int sum(const vector<int> & rel, int k) {
  int sum = 0;
  for (int i = 0; i < rel.size(); i++) {
    sum += abs(rel[i] - k);
  }
  return sum;
}

int min(vector<int> & rel) {
  if (rel.size() == 1)
    return 0;
  sort(rel.begin(), rel.end());
  int mid = rel.size() / 2;
  return sum(rel, rel[mid]);
}

int main() {
  int n = 0;
  cin >> n;
  for (int i = 0; i < n; i++) {
    int r = 0;
    cin >> r;
    vector<int> rel(r);
    int j;
    for (j = 0; j < r; j++) {
      cin >> rel[j];
    }
    cout << min(rel) << endl;
  }
}