[Vijos]P1225 拯救世界-紧急召集

题目

描述

话说在3085年,外星人打算来入侵地球,这个消息被我VIJOS国的情报部门秘密截获,于是便打算联系世界各个国家,一起研究商量对策。

由于每个国家所需派的技术员人数不同,所以目前无法决定到底要在哪个国家设置个研究所进行研究,幸运的是所有国家都在一条直线上,现在知道每个国家与我国的距离和该国的研究员人数。请你为他们决定一下到底在那个国家建立研究所可以使所有研究员集中到该国的费用最小。

格式

输入格式

输入文件每一行描述一个国家的信息。

首先是该国派出的技术员人数,紧跟着的是这个城市相对于我国的距离,最后是国家的名称。

输出格式

输出文件只需要一行,即研究所设定的国家名称。

样例1

样例输入1

7 9289 JAPAN
5 8523 AMERICA
3 5184 CHINA
8 2213 VIJOS
10 0 DDS

样例输出1

VIJOS

限制

1s内出解

提示

对于30%的数据,国家数不大于100。

对于60%的数据,国家数不大于500。

对于全部的数据,国家数不大于5000。

题解

刚开始想错了,以为将人数*距离排个序选中位数,然后就按这个思路交了好几次,然后我的AC率……

这个思路是完全错误的,这个方法应该只适用于不带权的情况,PS:求中位数有一个 O(n) 的快速选择算法,感兴趣的可以自己翻一下算法导论.说了这么多都是扯淡,下面说一下正确的做法.

先根据距离排一个序,然后就可以从前往后递推,计算出前面所有国家到当前国家的费用和,很容易写出递推公式:
C[0].lp = C[0].lc = 0
C[i].lp = C[i - 1].lp + C[i - 1].p
C[i].lc = C[i - 1].lc + C[i].lp * (C[i].dis - C[i - 1].dis)
其中C[i].lp表示前面的国家一共有多少人, C[i].lc表示前面国家的费用.

从后往前递推,计算出后面面所有国家到当前国家的费用和,递推公式也可以类似的写出,然后扫一遍找两个相加的最小值即可.

还是看代码比较清楚:

#include
#include
#include
using namespace std;
const int maxn = 5010;
struct Country
{
  double p, dis, lc, rc, lp, rp;
  string name;
  bool operator < (const Country& a) const
  {
    return dis < a.dis;
  }
}C[maxn];
int n = 0, ans = 0;
int main()
{
  while(cin >> C[n].p >> C[n].dis >> C[n].name)
    n++;
  sort(C, C + n);
  C[0].lp = C[0].lc = C[n - 1].rp = C[n - 1].rc = 0;
  for(int i = 1; i < n; i++)
  {
    C[i].lp = C[i - 1].lp + C[i - 1].p;
    C[i].lc = C[i - 1].lc + C[i].lp * (C[i].dis - C[i - 1].dis);
  }
  for(int i = n - 2; i >= 0; i--)
  {
    C[i].rp = C[i + 1].rp + C[i + 1].p;
    C[i].rc = C[i + 1].rc + C[i].rp * (C[i + 1].dis - C[i].dis);
  }
  for(int i = 0; i < n; i++)
    if(C[i].lc + C[i].rc < C[ans].lc + C[ans].rc)
      ans = i;
  cout << C[ans].name << endl;
  return 0;
}

你可能感兴趣的:(Vijos,排序)