小結啥啊 很久之前寫的 不過現在忘了 來復習一下 不過這種題 寫暴力 也是很簡單啊 但是分少啊qwq
1 歐式距離 也就是我們常說的 歐幾里得距離 也就是
$z=\sqrt{x^2+y^2}$ 然后也就是對應到平面上 求兩個點的距離的時候 用橫縱坐標之差 然后開根號 即可
就是 現在在班里學習文化課 的同學 數學課本上的 計算公式 很好理解 不過 這種一般用於 題目給定你是 這樣計算距離
至於 優化 我沒見過什么 比較大的優化吧 或許 是我寫題少
那么存在一個例題 就是奶酪qwq 奶酪好啊 題目
這里定義了一下 三維平面的計算公式 不過是多了一個維度z 此時距離 我們按照題目給定的計算方法
顯然 我們發現這是一個 並查集維護連通性的問題 那么怎么聯通 一定是兩個球體中心之間的距離 小於等於給定的 2*r 才能相切或者相交
由於我們發現開根號是此類問題的不好處理的地方 那么我們不妨考慮 此時兩邊平方 即可
#include<bits/stdc++.h> typedef long long ll; const ll N=1100; ll T,n,h,r,x[N],y[N],z[N],father[N],d[N],u[N]; template<typename T>inline void read(T &x) { x=0;T f=1,ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x*=f; } inline long long dis(ll i,ll j) { return (ll)(x[i]-x[j])*(x[i]-x[j])+(ll)(y[i]-y[j])*(y[i]-y[j])+(ll)(z[i]-z[j])*(z[i]-z[j]); } ll fa[N + 5]; ll find(ll x) { return fa[x]==x?x:fa[x]=find(fa[x]); } inline void Union(ll x, ll y) { fa[find(x)]=find(y); } signed main() { read(T); while(T--) { read(n);read(h);read(r); memset(x,0,sizeof(x)); memset(y,0,sizeof(y)); memset(z,0,sizeof(z)); memset(u,0,sizeof(u)); memset(d,0,sizeof(d)); for(ll i=1;i<=n;++i) fa[i]=i; for(ll i=1;i<=n;++i) read(x[i]), read(y[i]), read(z[i]); for(ll i=1;i<=n;++i) for(ll j=1;j<i;++j) if(dis(i,j)<=(ll)4*r*r) Union(i,j); bool flag=0; for(ll i=1;i<=n;++i) { if(z[i]-r<=0) d[find(i)]=1; if(z[i]+r>=h) u[find(i)]=1; } for(int i=1;i<=n;++i) { if(d[i]&&u[i])flag=1; if(flag)break; } puts(flag ? "Yes" : "No"); } return 0; }
然后就要提到我們的曼哈頓距離了
定義曼哈頓距離是
在二維空間內,兩個點之間的曼哈頓距離為它們橫坐標之差的絕對值與縱坐標之差的絕對值之和。
設點 A($x_1$,$y_1$) B($x_2$,$y_2$),則 A,B 之間的曼哈頓距離用公式可以表示為:
$d(A,B) = \left | x_1 - x_2\right | + \left | y_1 - y_2 \right |$
對於n維平面的計算公式
那么我們顯然 發現一個東西 這玩意都是非負的 並且自己到自己是0唄(廢話
並且 我們發現三個點之間的距離 存在一個三角不等式 d(i,j)≤d(i,k)+d(k,j)
也就是說 在曼哈頓距離的意義下 任意兩個點之間的直接距離 不會大於 途徑其他點的距離 原來做過一道 圖論 就是這樣建圖的
那么一般是什么問題 計算距離的時候是曼哈頓距離呢?
其實大多是網格圖 或者國際象棋。
在國際象棋棋盤上,車從一個格子走到另一個格子的最短距離就是曼哈頓距離。
若網格圖上的一個點只能到上下左右 4 個點,且到這 4 個點的距離都相同,則該網格圖上兩點的距離也為曼哈頓距離。、
讓你求 若干點對 求 曼哈頓距離 最大的 點對 n是5e4的
根據題意,對於式子$d(A,B) = \left | x_1 - x_2\right | + \left | y_1 - y_2 \right |$ 我們可以分成四種情況考慮:
第一種情況:x1−x2≥0,y1−y2≥0
那么他們之間的距離 就是 x1-x2+y1-y2=(x1+y1)- (x2+y2)
第二種情況 x1−x2<0,y1−y2≥0
那么他們之間的距離 就是 x2-x1+y1-y2=(x2-y2)- (x1-y1)
第三種情況 x1−x2≥0,y1−y2<0
那么他們之間的距離 就是 x1-x2+y2-y1=(x1-y1)- (x2-y2)
第四種情況 x1−x2<0,y1−y2<0
那么他們之間的距離 就是 x2-x1+y2-y1=(x2+y2)- (x1+y1)
那么 我們不免發現 距離
要么 之和 x+y 有關 要么 只和 x-y 有關 那么答案就是
max{max{xi+yi}−min{xi+yi},max{xi−yi}−min{xi−yi}}
#include<bits/stdc++.h>
using namespace std; int n,x,y; template<typename T>inline void read(T &x) { x=0;T f=1,ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x*=f; } const int N=(1<<30); int max1=-N,max2=-N,min1=N,min2=N; int main() { read(n); for(int i=1;i<=n;i++) { read(x); read(y); max1=max(max1,x+y); min1=min(min1,x+y); max2=max(max2,x-y); min2=min(min2,x-y); } cout<<max((max1-min1),(max2-min2)); return 0; }
要理解一下這個轉化
接下來 介紹一下切比雪夫距離
在二維空間內,兩個點之間的切比雪夫距離為它們橫坐標之差的絕對值與縱坐標之差的絕對值的最大值。
設點 A(x1,y1),B(x2,y2) ,則 A,B之間的切比雪夫距離用公式可以表示為:
$d(A,B) = \max(\left | x_1 - x_2\right | , \left | y_1 - y_2\right | )$
同樣對於 n維的情況
切比雪夫距離 的一般模型:
在國際象棋棋盤上,國王與王后從一個格子走到另一個格子的最短距離都是切比雪夫距離。
若網格圖上的一個點只能到周圍 8 個點,且到這 8 個點的距離都相同,則該網格圖上兩點的距離也為切比雪夫距離。
那么重點來了
我們現在要探討二維曼哈頓距離與切比雪夫距離的相互轉化
我這里簡單證明一下吧
或者我還看過一個比較優秀的證明
假設 A(x1,y1),B(x2,y2) ,A,B 兩點的曼哈頓距離為:
我們很容易發現,這就是 (x1+y1,x1−y1),(x2+y2,x2−y2) 兩點之間的 切比雪夫距離。
所以將每一個點 (x,y)轉化為 (x+y,x−y) ,新坐標系下的 切比雪夫距離 即為原坐標系下的 曼哈頓距離。
同理 A,B 兩點的 切比雪夫距離 為:
而這就是 $\displaystyle \left( \frac{x_1+y_1}{2},\frac{x_1-y_1}{2} \right),\left( \frac{x_2+y_2}{2},\frac{x_2-y_2}{2} \right)$ 兩點之間的 曼哈頓距離。
所以將每一個點 (x,y) 轉化為 $\displaystyle \left( \frac{x+y}{2},\frac{x-y}{2}\right)$ 新坐標系下的 曼哈頓距離 即為原坐標系下的 切比雪夫距離。
也就是 兩個東西 可以相互轉化 那么 對於有些題目 我們就要注意到 怎么計算簡單了
在觀察 上面那個問題 求曼哈頓距離 最大的點對 我們考慮轉化成切比雪夫距離 那么 就是(x,y) 轉化成 (x+y,x-y)
所求的答案就變為 max{max{∣xi−xj∣,∣yi−yj∣}}
在所有點中,橫坐標之差的最大值和縱坐標之差的最大值都有可能成為答案,
所以我們只需要預處理出 x,y 的最大值和最小值即可。時間復雜度為 O(n) 。
例題下午會給出 因為 我現在眼睛太疼了。 不寫了。
我好了 我來寫文章了
我們發現 直接切比雪夫 計算是比較麻煩的 因為處理max 都是至少n^2 的
所以 我們考慮 轉化為曼哈頓距離 將每一個點 (x,y) 轉化為 $\displaystyle \left( \frac{x+y}{2},\frac{x-y}{2}\right)$
考慮 這個時候 我們進行的就是若干求和 考慮都是絕對值 那么存在大小關系
所以 我們不妨考慮 排序!
枚舉所選的點 i ,我們只需要計算其它點到它的曼哈頓距離和即可。
如果某個點 j 的橫坐標 xj≤xi ,則它的對總距離的貢獻為 xi−xj ,反之則為 xj−xi 。
這樣就可以分兩種情況討論了。
設前 k 個點的橫坐標都 ≤xi ,那么所有點橫坐標的貢獻和為
而對於前綴和 我們可以預處理 然后(1)查詢 即可 對於縱坐標也是這樣 此時我們使用stl lower_bound 就是一個不錯的選擇呢
#include<bits/stdc++.h> using namespace std; #define N 100100 typedef long long ll; ll n,a,b,p[N],x[N],y[N],q[N],prex[N],prey[N],ans=0x7fffffffffffffff; template<typename T>inline void read(T &x) { x=0;T f=1,ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x*=f; } int main() { read(n); for(int i=1;i<=n;i++) { read(a); read(b); x[i]=p[i]=a+b; y[i]=q[i]=a-b; } sort(p+1,p+n+1); sort(q+1,q+n+1); for(int i=1;i<=n;i++) { prex[i]=prex[i-1]+p[i]; prey[i]=prey[i-1]+q[i]; } for(int i=1;i<=n;i++) { int posx=lower_bound(p+1,p+n+1,x[i])-p; int posy=lower_bound(q+1,q+n+1,y[i])-q; ll sumx=0,sumy=0; sumx=(ll)posx*x[i]-prex[posx]+prex[n]-prex[posx]-(ll)(n-posx)*x[i]; sumy=(ll)posy*y[i]-prey[posy]+prey[n]-prey[posy]-(ll)(n-posy)*y[i]; ans=min(ans,sumx+sumy); } cout<<(ans/2)<<endl; return 0; }
當然 這里我也有一個 手寫二分的代碼 有同學抬杠stl慢
Q次詢問 每次給出一個 點(s,t) 求 所有點到它的切比雪夫距離
#include<bits/stdc++.h> using namespace std; typedef long long ll; template<typename T>inline void read(T &x) { x=0;T f=1,ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x*=f; } const int N=1010000; ll T,n,w,s,t,a,b,X[N],Y[N],p[N],q[N],prex[N],prey[N]; inline int find(int x) { if(p[n]<=x)return n; if(p[1]>=x)return 0; int l=1,r=n; while(l+1<r) { int mid=(l+r)>>1; if(p[mid]>=x)r=mid; else l=mid; } if(p[r]<=x)return r; return l; } inline int calc(int x) { if(q[n]<=x)return n; if(q[1]>=x)return 0; int l=1,r=n; while(l+1<r) { int mid=(l+r)>>1; if(q[mid]>=x)r=mid; else l=mid; } if(q[r]<=x)return r; return l; } int main() { read(T); while(T--) { read(n); read(w); for(int i=1;i<=n;i++) { read(a); read(b); X[i]=p[i]=a+b,Y[i]=q[i]=a-b; } sort(p+1,p+n+1); sort(q+1,q+n+1); for(int i=1;i<=n;i++) { prex[i]=prex[i-1]+p[i]; prey[i]=prey[i-1]+q[i]; } for(int i=1;i<=w;i++) { read(s); read(t); ll xx=s+t,yy=s-t; int posx=find(xx); int posy=calc(yy); ll sumx=0,sumy=0; //cout<<posx<<' '<<posy<<endl; sumx=(ll)posx*xx-prex[posx]+prex[n]-prex[posx]-(ll)(n-posx)*xx; sumy=(ll)posy*yy-prey[posy]+prey[n]-prey[posy]-(ll)(n-posy)*yy; printf("%lld\n",(sumx+sumy)/2); } } return 0; }