P1429 平面最近點對(加強版)
阿新 • • 發佈:2021-09-03
神奇分治,沒想到吧
按照x座標排序。把點分成兩部分。
遞迴統計內部答案
分治主要考慮怎麼合併兩部分的答案:
首先要距離中間點小於當前ans的點。
然後把這些數按照y排序。
列舉即可。但是我們要記得及時退出。
可以證明對於一個左邊的點,右邊需要判定的點在三個以內。因為需要保證同側不會出現更優答案。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<map> #include<stack> #include<vector> #include<set> #include<iomanip> #include<ctime> #include<cstdlib> #include<cmath> using namespace std; #define orz cout<<"lyakioi!!!!!!!!!!!!!!!!!"<<endl inline int r(){int s=0,k=1;char c=getchar();while(!isdigit(c)){if(c=='-')k=-1;c=getchar();}while(isdigit(c)){s=s*10+c-'0';c=getchar();}return s*k;} int n,tmp[1000001],cnt; struct node { double x,y; }a[1000005]; bool cmp(node x,node y) { if(x.x==y.x)return x.y<y.y; return x.x<y.x; } bool pmc(int x,int y) { return a[x].y<a[y].y; } double dfs(int l,int r)//當前區間求出l-r的答案 { double ans=1e10; if(l>=r)return ans; int mid=(l+r)/2; ans=min(ans,dfs(l,mid)); ans=min(ans,dfs(mid+1,r)); cnt=0; for(int i=l;i<=r;i++) if(fabs(a[i].x-a[mid].x)<=ans)tmp[++cnt]=i; sort(tmp+1,tmp+cnt+1,pmc); for(int ii=1;ii<=cnt;ii++) for(int jj=ii+1;jj<=cnt;jj++) { int i=tmp[ii];int j=tmp[jj]; double dis=(a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y); dis=sqrt(dis); ans=min(ans,dis); // if(a[j].y-a[i].y>ans)break; } return ans; } int main() { n=r(); for(int i=1;i<=n;i++) { a[i].x=r(); a[i].y=r(); } sort(a+1,a+n+1,cmp); printf("%.4lf",dfs(1,n)); }