poj 3714 Raid (分治+一點鴿巢原理)
阿新 • • 發佈:2018-12-15
題目連結:poj 3714
題意:給個n,首先個n個點的位置,再給n個人的位置,問你,人到點最短距離是多少?
參考部落格:http://yzmduncan.iteye.com/blog/1432880
https://www.cnblogs.com/captain1/p/9607559.html
題解:
感覺看了這兩篇部落格,都不需要過多的補充,前人栽的樹已經很涼了,但我還是要解釋下為什麼跟鴿巢原理產生了微妙的聯絡,為什麼?因為博主沒解釋。首先,我先假設你們都看過這兩篇部落格,因為照搬進來就沒多大意思了。
第二篇部落格中有段話:對於C1中的每一個點k,能與之配對更新最短距離的,一定是C2中一個長為 dis,高為2*dis的一個矩形之內的點。再者,因為S2中每兩個點的距離必須>=dis,所以這個矩形之內最多隻可能有6個點。
就是這段話,這結論寫的真~有~水~平,一點由來也不說,反正我剛看是不明白為什麼最多有6個點,當然可能有人沒遇到這個疑問,可以略過不看。
然後細想一下,確實是這樣的,我們想下,在這個dis*2dis的矩形中,我們要想每兩個點的距離都大於等於dis,那麼我們最多放4個點在四個不起眼的角落夾縫生存以及放2個點在兩條高的中間,如圖所示:
看圖就清楚了,結論就容易出來了,在矩形中,要滿足每兩個點必須大於等於dis,
最多放6個點,在放多一個就不滿足了。
這個我們就把它說成是鴿巢定理了。
就差不多是那樣了,有“最多”,“至少” 這些字眼。
程式碼:
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long LL; const int maxn=200010; #define INF 0x3f3f3f3f struct point{ double x,y; int id; }node[maxn]; int temp[maxn]; bool cmpxy(point a,point b){ if(a.x-b.x!=1e-8) return a.x<b.x; else return a.y<b.y; } bool cmpy(int a,int b){ return node[a].y<node[b].y; } double dist(int a,int b){ if(node[a].id!=node[b].id) return sqrt((node[a].x-node[b].x)*(node[a].x-node[b].x)+(node[a].y-node[b].y)*(node[a].y-node[b].y)); else return INF; } double solve(int left,int right) ///分治 { double d=INF; if(left==right) return d; if(left+1==right) return dist(left,right); int mid=(left+right)/2; double d1=solve(left,mid); double d2=solve(mid+1,right); if(d1<d2) d=d1; else d=d2; int k=0; for(int i=left;i<=right;i++) if(fabs(node[mid].x-node[i].x)-d<=1e-8) temp[++k]=i; sort(temp+1,temp+k+1,cmpy); ///排序,按y for(int i=1;i<=k;i++) { for(int j=i+1;j<=k;j++){ if(fabs(node[temp[j]].y-node[temp[i]].y)>d) break; double d3=dist(temp[i],temp[j]); if(d>d3&&node[temp[i]].id!=node[temp[j]].id) d=d3; } } return d; } int main() { int ncase,n; scanf("%d",&ncase); while(ncase--) { int n; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%lf%lf",&node[i].x,&node[i].y); node[i].id=1; ///1表示點位置 } for(int i=n+1;i<=n*2;i++){ scanf("%lf%lf",&node[i].x,&node[i].y); node[i].id=2; ///2表示人的位置 } sort(node+1,node+1+2*n,cmpxy); ///排序,按x,y printf("%.3f\n",solve(1,n*2)); } return 0; }