题目大意
给你n个点,要你求一个点,横纵坐标是范围在0到100000之间的整数,使得该点到所有给定的点的切比雪夫距离最小。
n≤100000 0≤坐标范围≤100000
预备
首先两个点(x1,y1),(x2,y2)的切比雪夫距离为
max(|x1−x2|,|y1−y2|)
然后把每个点的坐标变成(x+y,x-y),两个点切比雪夫距离变成了它们的曼哈顿距离。
满分算法
方法就很显然了。把每个坐标转成(x+y,x-y),然后由于求的是曼哈顿距离,可以把答案的横纵坐标分开来求,然后得到一个点(x,y)
然后把这个点坐标转回去就可以了吗?
不行!
答案求的是整点,然而这样求出来的坐标,奇偶性可能不一样,也就是转回去后可能是小数(如样例中求出的答案,转回去坐标是(1.5,1.5))。所以,对于奇偶性相同,直接转回去即可,如果不同,答案就在这个点上下左右四个整点中找。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=100005;
typedef long long LL;
int n,x[maxn],y[maxn],xx[maxn],yy[maxn],ansx,ansy,X,Y;
LL ans,s;
double tx,ty;
int main()
{
scanf("%d",&n);
for (int i=0;i<n;i++)
{
scanf("%d%d",&x[i],&y[i]);
xx[i]=x[i]+y[i];
yy[i]=x[i]-y[i];
}
int j=0;
sort(xx,xx+n);
sort(yy,yy+n);
X=xx[n/2]; Y=yy[n/2];
if ((X+Y)%2==0)
{
ansx=(X+Y)/2;
ansy=(X-Y)/2;
ans=0;
for (int i=0;i<n;i++) ans+=max(abs(ansx-x[i]),abs(ansy-y[i]));
printf("%lld\n",ans);
}else
{
tx=(double)(X+Y)/2;
ty=(double)(X-Y)/2;
ans=1e17;
for (int a=0;a<2;a++)
{
int p=tx+a-0.5;
if (p>=0 && p<=1e5)
{
for (int b=0;b<2;b++)
{
int q=ty+b-0.5;
if (q>=0 && q<=1e5)
{
s=0;
for (int i=0;i<n;i++) s+=max(abs(p-x[i]),abs(q-y[i]));
if (s<ans) ans=s;
}
}
}
}
printf("%lld\n",ans);
}
return 0;
}