P1429 平面最近点对(加强版)
神奇分治,没想到吧
按照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));
}
本文来自博客园,作者:lei_yu,转载请注明原文链接:https://www.cnblogs.com/lytql/p/15224594.html