1. 程式人生 > >曼哈頓距離&切比雪夫距離

曼哈頓距離&切比雪夫距離

什麼是切比雪夫距離?什麼是曼哈頓距離?

傻傻分不清,沒關係,看:

曼哈頓距離

設平面空間記憶體在兩點,它們的座標為(x1,y1),(x2,y2)

則dis=|x1−x2|+|y1−y2|

即兩點橫縱座標差之和

切比雪夫距離

設平面空間記憶體在兩點,它們的座標為(x1,y1),(x2,y2)

則dis=max(|x1−x2|,|y1−y2|)

即兩點橫縱座標差的最大值

 

比如這個圖,A,B兩點的曼哈頓距離就是dis=(2-(-2))+(3-0)=7

切比雪夫距離就是dis=max(2-(-2),(3-0))=4

既然都提到這兩個距離了,就免不了要講講它們的相互轉化

將一個點(x,y)的座標變為(x+y,x−y)後,原座標系中的曼哈頓距離 = 新座標系中的切比雪夫距離

將一個點(x,y)的座標變為(x+y)/2,(x-y)/2後,原座標系中的切比雪夫距離 = 新座標系中的曼哈頓距離

這個證明也很容易,有興趣的同學可以來皮一下

我就不在這裡贅述了

然而有什麼用呢??這麼多奇奇怪怪的定義,真是讓人摸不著頭腦

但事實上,可有用了呢

切比雪夫距離由於要求max 很多時候不是很好優化,對於一個點,計算其他點到該的距離的複雜度為O(n)(因為要列舉)

而曼哈頓距離只有求和以及取絕對值兩種運算,我們把座標排序後可以去掉絕對值的影響,進而用字首和優化,可以把複雜度降為O(1),也可以支援很多次的運算

而有一個細節需要注意一下:

在切比雪夫距離轉曼哈頓距離的時候,座標本是要除以2的,但考慮到精度的問題,我們一般都會將除以2 這一步操作放到最後 這樣也是正確的,形象的理解可以說成,曼哈頓座標系是通過切比雪夫座標系旋轉45度後,再縮小到原來的一半得到的。

#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;
}