题意:
给出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
#include
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
#include
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;
}