曼哈頓距離與切比雪夫距離的互化


\(\\\)

曼哈頓距離


對於兩個點\((x_1,y_1),(x_2,y_2)\),定義他們的曼哈頓距離為\(|x_1-x_2|+|y_1-y_2|\),即兩坐標軸分別討論差值再求和。

對於曼哈頓距離相同的點,他們分布在同一橫縱截距且截距相同的直線上。

圖中每一個正方形邊界上的整點到原點的曼哈頓距離相同。

\(\\\)

切比雪夫距離


對於兩個點\((x_1,y_1),(x_2,y_2)\),定義他們的曼哈頓距離為\(max\{|x_1-x_2|,|y_1-y_2|\}\),即兩坐標軸分別討論差值取最大。

對於切比雪夫距離相同的點,他們分布在以原點為中心的正方形邊界上。

圖中每一個正方形邊界上的整點到原點的曼哈頓距離相同。

\(\\\)

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


考慮曼哈頓距離的表達式:\(|x_1-x_2|+|y_1-y_2|\),其實可以表示成:

\(\begin{align}max\{x_1-x_2+y_1-y_2,x_1-x_2+y_2-y_1,x_2-x_1+y_1-y_2,x_2-x_1+y_2-y_1\}\end{align}\)

考慮將兩個點變化為\((x_1+y_1,x_1-y_1),(x_2+y_2,x_2-y_2)\)

那么變化后兩點的切比雪夫距離為\(max((|(x_1+y_1)-(x_2+y_2)|,|(x_1-y_1)-(x_2-y_2)|)\)

若原來兩點曼哈頓距離為\(x_1-x_2+y_1-y_2\)\(x_2-x_1+y_2-y_1\)時,都可以表示為\(|(x_1+y_2)-(x_2+y_2)|\)

若原來兩點曼哈頓距離為\(x_1-x_2+y_2-y_1\)\(x_2-x_1+y_1-y_2\)時,都可以表示為\(|(x_1-y_1)-(x_2-y_2)|\)

將每一個點\((x,y)\)轉化為\((x+y,x-y)\),新坐標系下的切比雪夫距離即為原坐標系下曼哈頓距離。

\(\\\)

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


按照剛才的思路再還原回去即可。

將每一個點\((x,y)\)轉化為\((\frac{x+y}{2},\frac{x-y}{2})\),新坐標系下的曼哈頓距離即為原坐標系下切比雪夫距離。

這個轉化一般比較常用,曼哈頓距離一般可以通過排序前綴和的方式降低計算復雜度。

注意到除法如果向下取整可能會使答案不正確,所以考慮先不除以\(2\),最后求完答案再除以\(2\)也是一樣的,形象的理解可以說成,曼哈頓坐標系是通過切比雪夫坐標系旋轉\(45^{\circ}\)后,再縮小到原來的一半得到的。

\(\\\)

一道例題


\(N\)個二位平面上的點,定義每一個點到其八連通的點的距離為\(1\)

選一個點,使得剩下所有點到該點的距離之和最小,求出這個距離之和。

  • \(N\in [0,10^5]\)

\(\\\)

題意即為求切比雪夫距離之和最小,暴力的做法是\(N^2\)的。

考慮將切比雪夫距離轉化為曼哈頓距離,我們將橫縱坐標分開排序求前綴和,這樣既可快速求出,以一個點為中心,其他點到這個點的曼哈頓距離之和。

具體的做法是將兩個坐標分開討論,每次找到當前點在排序后數組的位置\(p\)

那么它前面的點坐標都小於當前點,累加的答案為\(p\times x[i]-sum_p\)

后面的點的坐標都大於當前點,反過來累加答案,為\((sum_n-sum_p)-(n-p)\times x[i]\)

對所有的點都求一遍,取最小值即可,復雜度\(\text O(NlogN)\)

\(\\\)

#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 100010
#define R register
#define gc getchar
#define inf 900000000000000000
using namespace std;
typedef long long ll;

inline ll rd(){
  ll x=0; bool f=0; char c=gc();
  while(!isdigit(c)){if(c=='-')f=1;c=gc();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
  return f?-x:x;
}

ll n,ans=inf,x[N],y[N],sx[N],sy[N],sumx[N],sumy[N];

int main(){
  n=rd();
  for(R ll i=1,xx,yy;i<=n;++i){
    xx=rd(); yy=rd();
    sx[i]=x[i]=xx+yy; sy[i]=y[i]=xx-yy;
  }
  sort(sx+1,sx+1+n);
  sort(sy+1,sy+1+n);
  for(R ll i=1;i<=n;++i){
    sumx[i]=sumx[i-1]+sx[i];
    sumy[i]=sumy[i-1]+sy[i];
  }
  for(R ll i=1,res;i<=n;++i){
    ll px=lower_bound(sx+1,sx+1+n,x[i])-sx;
    ll py=lower_bound(sy+1,sy+1+n,y[i])-sy;
    res=px*x[i]-sumx[px]+sumx[n]-sumx[px]-(n-px)*x[i];
    res+=py*y[i]-sumy[py]+sumy[n]-sumy[py]-(n-py)*y[i];
    ans=min(ans,res>>1);
  }
  printf("%lld\n",ans);
  return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM