Description

某天gameboy玩魔兽RPG。有一个任务是在一个富含金矿的圆形小岛上建一个基地,以最快的速度采集完这个小岛上的所有金矿。这个小岛上有n(0<n<1000000)个金矿,每个金矿的矿藏量是相等的。而且这个小岛的地势非常平坦,所以基地可以建在小岛的任何位置,每个金矿的采矿速度只跟矿藏到基地的路程长度有关。为了不让这个任务太无聊,游戏设计者对这个小岛施了个“魔法”,规定矿工在小岛上只能正南正北正西正东走。也就是说矿工不能斜着在岛上走。

这个小岛在一个二维直角坐标系中描述。

你的任务就是帮gameboy找一个建造基地的位置,使矿工能以最快的速度采完所有矿。
 

Input

输入数据有多组。每组数据的第一行是一个正整数n(0<n<1000000),表示小岛上有n个金矿。在接下来的n行中,每行有两个实数x,y,表示其中一个金矿的坐标。n=0表示输入数据结束。
 

Output

每一组输入数据对应一行输出,输出两个实数x,y(保留小数点后两位),也就是你找到的建造基地的位置坐标。如果坐标不唯一,可以任选一个输出。
 

Sample Input

4 1.0 1.0 3.0 1.0 3.0 3.0 1.0 3.0 0
 

Sample Output

2.00 2.00
 
题意:求坐标平面上一点与已知点距离和的最小值。
    如果只有一维,取中位数时距离和最小。
   证明:假设A1<=A2<=...<=An。y=|x-A1|+|x-A2|+...+|x-An|表示数轴上一点x到数轴上n个上点(分别为A1、A2...An)的距离之和

1) 先考虑两个数的情况:y=|x-M|+|x-N| (M<=N)。根据两点之间线段距离最短,当x在[M, N]区间内任取一点,y都具有最小值|N-M|,当x不在[M, N]区间之内的时候,y>|N-M|

2) 再考虑n个数的情况。为了使y最小,x显然应该取在[A1, An]区域内。再根据1)的结论,在[A1, An]内取任何值,|x-A1|+|x-An|的大小都为|An-A1|
于是问题转变为求y=|x-A2|+|x-A3|+...|x-An-1|的最小值,x应该在[A2, An-1]内
这样逐层剥皮,最后剩下1个(对应n为奇数)或者2个数(对应n为偶数)。如果最后剩下1个数,那么x就应该取这个数,这个数显然为A1、A2、...An的中位数。如果最后剩下2个数,取这两个数构成的区域内任一个数都可以,特殊的,就取较小的那个数,它也是A1、A2、...An的中位数。
 
    题中给的是二维,但由于求的是坐标距离,不是几何距离,所以,可以当成一维来做。
 
代码如下:
 

#include <iostream>
#include <algorithm>

using namespace std;

struct Point
{
 double x, y;
}point[1000000];

bool com1(Point a, Point b)
{
 return a.x > b.x;
}
bool com2(Point a, Point b)
{
 return a.y > b.y;
}

int main()
{
 int n;
 while (cin >> n, n)
 {
  double x, y;
  for (int i = 0; i < n; i++)
  {
   cin >> point[i].x >> point[i].y;
  }
  
  sort(point, point + n, com1);
  x = (n % 2 == 0) ? (point[n / 2 - 1].x + point[n / 2].x) / 2 : point[n / 2].x;
  sort(point, point + n, com2);
  y = (n % 2 == 0) ? (point[n / 2 - 1].y + point[n / 2].y) / 2 : point[n / 2].y;
  
  printf("%.2lf %.2lf\n", x, y);
 }
 return 0;
}

posted on 2013-05-11 19:47  认真的看我  阅读(150)  评论(0编辑  收藏  举报