【模板】平面最近点对-分治

传送门:洛谷-平面最近点对


题意

给定平面上n个点,找出其中的一对点的距离,使得在这n个点的所有点对中,该距离为所有点对中最小的。


数据范围

2≤n≤200000


题解

一、分治
按x排序,左右分治,边界处理一下就好了。

代码:

#include
#include
#include
#include
#include 
#define db double
const int INF=0x7fffffff;
using namespace std;
typedef long long ll;
const int N=2e5+10;
struct P{
    int x,y;
}p[N];
int n,in[N],cnt;
inline db sqr(int x){return (db)x*(db)x;}
inline db fab(db x){return x<0 ? -x:x;}
inline db min(db a,db b){return ainline db dist(P a,P b){return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));}
bool cmp(const P &a,const P &b){
   if(a.x==b.x){
      return a.yreturn a.xbool cmq(const int &a,const int &b){return p[a].yinline db merge(int l,int r)
{
    db d=INF;
    if(l==r) return d;
    if(l+1==r) return dist(p[l],p[r]);
    int mid=(l+r)>>1;
    db pa=merge(l,mid);
    db pb=merge(mid+1,r);
    d=min(pa,pb);   
    cnt=0;
    for(int i=l;i<=r;i++){
        if(fab(p[i].x-p[mid].x)//<=
           in[++cnt]=i;
        }
    }
    sort(in+1,in+cnt+1,cmq);
    for(int i=1;i<=cnt;i++){
        for(int j=i+1;j<=cnt && p[in[j]].y-p[in[i]].yreturn d;
}

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&p[i].x,&p[i].y);
    }
    sort(p+1,p+n+1,cmp);
    printf("%.4lf\n",merge(1,n));
    return 0;
}

二、扫描
按y排序,从上往下扫,优化看代码。

代码:

#include
#include
#include
#include
#include 
#define db double
const int INF=0x7fffffff;
using namespace std;
typedef long long ll;
const int N=2e5+10;
struct P{
    int x,y;
}p[N];

db ans;
int n,head[N],to[N],nxt[N],cnt,tot;
inline db sqr(int x){return (db)x*(db)x;}
inline db fab(db x){return x<0 ? -x:x;}
inline db min(db a,db b){return areturn sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));}
inline void lk(int u,int v)
{
    nxt[++tot]=head[u];head[u]=tot;to[tot]=v;
}

inline bool cmq(const P &a,const P &b){
    if(a.y==b.y) return a.xx; 
    return a.yy;
}

int main(){
    ans=INF;
    scanf("%d",&n); 
    for(int i=1;i<=n;i++){
       scanf("%d%d",&p[i].x,&p[i].y);
    }
    sort(p+1,p+n+1,cmq);
    lk(1,1);++cnt;
    for(int i=2;i<=n;i++){
        if(p[i].y!=p[i-1].y){
            ++cnt;
        }else{
            ans=min(ans,(db)(p[i].x-p[i-1].x));
        }
        lk(cnt,i);
    }
    for(int i=1;iint mx=i+1;
        while(mx<=cnt && (db)(p[to[head[mx]]].y-p[to[head[i]]].y)<=ans){
            int qw=head[mx];
            for(int e,k=head[i];k && qw ;k=nxt[k]){
                int ty=to[k];
                for(;qw;qw=nxt[qw]){
                    while(nxt[qw]!=0 && p[to[nxt[qw]]].x>=p[ty].x){
                        qw=nxt[qw];
                    }
                    e=to[qw];
                    if(p[e].x<=p[ty].x){
                        ans=min(dist(p[e],p[ty]),ans);
                        break;
                    }
                    ans=min(dist(p[e],p[ty]),ans);
                }
            }
            mx++; 
        }
    }
    printf("%.4lf\n",ans);
    return 0;
}

你可能感兴趣的:(分治)