1012 - 曼哈顿距离&切比雪夫距离
什么是切比雪夫距离?什么是曼哈顿距离?
傻傻分不清,没关系,看:
曼哈顿距离
设平面空间内存在两点,它们的坐标为(x1,y1),(x2,y2)
则dis=|x1−x2|+|y1−y2|
即两点横纵坐标差之和
切比雪夫距离
设平面空间内存在两点,它们的坐标为(x1,y1),(x2,y2)
则dis=max(|x1−x2|,|y1−y2|)
即两点横纵坐标差的最大值
比如这个图,A,B两点的曼哈顿距离就是
切比雪夫距离就是
既然都提到这两个距离了,就免不了要讲讲它们的相互转化
将一个点(x,y)的坐标变为(x+y,x−y)后,原坐标系中的曼哈顿距离 = 新坐标系中的切比雪夫距离
将一个点(x,y)的坐标变为
后,原坐标系中的切比雪夫距离 = 新坐标系中的曼哈顿距离
这个证明也很容易,有兴趣的同学可以来皮一下
我就不在这里赘述了
然而有什么用呢??这么多奇奇怪怪的定义,真是让人摸不着头脑
但事实上,可有用了呢
切比雪夫距离由于要求max 很多时候不是很好优化,对于一个点,计算其他点到该的距离的复杂度为O(n)(因为要枚举)
而曼哈顿距离只有求和以及取绝对值两种运算,我们把坐标排序后可以去掉绝对值的影响,进而用前缀和优化,可以把复杂度降为O(1),也可以支持很多次的运算
而有一个细节需要注意一下:
在切比雪夫距离转曼哈顿距离的时候,坐标本是要除以2的,但考虑到精度的问题,我们一般都会将除以2 这一步操作放到最后
这样也是正确的,形象的理解可以说成,曼哈顿坐标系是通过切比雪夫坐标系旋转45度后,再缩小到原来的一半得到的。
是不是手痒痒了??来吧,练一道入门题 松鼠聚会(TJOI 2013)
#include<bits/stdc++.h>
#define ll long long
#define N 100009
#define in read()
using namespace std;
inline int read(){
char ch;int f=1,res=0;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
while(ch>='0'&&ch<='9'){
res=(res<<3)+(res<<1)+ch-'0';
ch=getchar();
}
return f==1?res:-res;
}
ll ans=1ll<<50ll,sumx[N],sumy[N];//一开始ans又初始小了~~~~~悲伤
int n,x[N],y[N],xx[N],yy[N];
ll solve(int now){//现在要到 n 的家里去
ll res=0;
int pos=lower_bound(xx+1,xx+n+1,x[now])-xx;
res+=1ll*pos*x[now]-sumx[pos]+sumx[n]-sumx[pos]-1ll*(n-pos)*x[now];
pos=lower_bound(yy+1,yy+n+1,y[now])-yy;
res+=1ll*pos*y[now]-sumy[pos]+sumy[n]-sumy[pos]-1ll*(n-pos)*y[now];
return res;
}
int main(){
n=in;
int i,j,k;
for(i=1;i<=n;++i) {
int a=in;int b=in;
x[i]=xx[i]=a+b;
y[i]=yy[i]=a-b;
}
sort(xx+1,xx+n+1);
sort(yy+1,yy+n+1);
for(i=1;i<=n;++i){
sumx[i]=sumx[i-1]+xx[i];
sumy[i]=sumy[i-1]+yy[i];
}
for(i=1;i<=n;++i)
ans=min(ans,solve(i));
cout<<ans/2;
return 0;
}