Problem Description
某天gameboy玩魔兽RPG。有一个任务是在一个富含金矿的圆形小岛上建一个基地,以最快的速度采集完这个小岛上的所有金矿。这个小岛上有n(0<n<1000000)个金矿,每个金矿的矿藏量是相等的。而且这个小岛的地势非常平坦,所以基地可以建在小岛的任何位置,每个金矿的采矿速度只跟矿藏到基地的路程长度有关。为了不让这个任务太无聊,游戏设计者对这个小岛施了个“魔法”,规定矿工在小岛上只能正南正北正西正东走。也就是说矿工不能斜着在岛上走。
这个小岛在一个二维直角坐标系中描述。
你的任务就是帮gameboy找一个建造基地的位置,使矿工能以最快的速度采完所有矿。
这个小岛在一个二维直角坐标系中描述。
你的任务就是帮gameboy找一个建造基地的位置,使矿工能以最快的速度采完所有矿。
Input
输入数据有多组。每组数据的第一行是一个正整数n(0<n<1000000),表示小岛上有n个金矿。在接下来的n行中,每行有两个实数x,y,表示其中一个金矿的坐标。n=0表示输入数据结束。
Output
每一组输入数据对应一行输出,输出两个实数x,y(保留小数点后两位),也就是你找到的建造基地的位置坐标。如果坐标不唯一,可以任选一个输出。
Sample Input
41.0 1.03.0 1.03.0 3.01.0 3.00
Sample Output
2.00 2.00
题意:
给出n个笛卡尔坐标系上的点,找到一点(可以不在n个点中)在x,y轴上投影,到其他所有点在x,y轴上投影,距离和最短
思路:
先将其转化为2个,求1维最短距离和的子问题。
刚开始以为是平均数,后来发现平均数并不是最优解,如1,5,6。
下面是一维上答案是中位数的证明(伪
设金矿有n个,每个金矿在ai 点( ai < a(i+1) )
n == 1 时,答案在a1点
n == 2 时,答案在区间[a1,a2]上
n > 2 时, 答案在 [a1,an],[a2,an-1]……上,所以答案是中间的点,或线段上。
--------------------------------------------------------------------------------------------------------------
另一种写法 和 伪证明
证明前提是已知点上必定存在答案,这个不会证明,凭直觉。
dp求每点到所有点距离和
//a为坐标点,dpa为a到其余点距离和
for(int i = 1; i < n; i++)
{
dpa[i] = dpa[i-1] + (a[i] - a[i-1])*i - (a[i] - a[i-1])*(n-i);
}
不难发现dpa是一个先减后增的数列,i>(n-i)时增,i<(n-i)时减。
这应该也可以说明答案是中位数吧。。。
--------------------------------------------------------------------------------------------------------------
代码:
直接求解:
#include<stdio.h>
#include<algorithm>
using namespace std;
double a[1000005], b[1000005];
int main()
{
int n;
while(scanf("%d",&n), n)
{
for(int i = 0; i < n; i++) scanf("%lf%lf",&a[i],&b[i]);
sort(a,a+n);
sort(b,b+n);
printf("%.2lf %.2lf\n",a[(n-1)/2], b[(n-1)/2]);
}
return 0;
}
dp:
#include<stdio.h>
#include<algorithm>
using namespace std;
double a[1000005], b[1000005], dpa[1000005], dpb[1000005];
int main()
{
int n;
// freopen("F:\\my.txt","w",stdout);
while(scanf("%d",&n), n)
{
for(int i = 0; i < n; i++) scanf("%lf%lf",&a[i],&b[i]);
sort(a,a+n);
sort(b,b+n);
for(int i = 1; i < n; i++)
{
dpa[0] = a[i] - a[0];
dpb[0] = b[i] - b[0];
}
for(int i = 1; i < n; i++)
{
dpa[i] = dpa[i-1] + (a[i] - a[i-1])*i - (a[i] - a[i-1])*(n-i);
dpb[i] = dpb[i-1] + (b[i] - b[i-1])*i - (b[i] - b[i-1])*(n-i);
}
int ans1 = 0, ans2 = 0;
for(int i = 1; i < n; i++)
{
if(dpa[i] < dpa[ans1]) ans1 = i;
if(dpb[i] < dpb[ans2]) ans2 = i;
}
printf("%.2lf %.2lf\n",a[ans1], b[ans2]);
}
return 0;
}