[P1427] 平面最近点对【加强版】 - 分治

暴力沿着 \(x\) 轴方向分治,每次合并时,利用当前已有 \(ans\),只保留 \((mid-ans,mid+ans)\) 内的点,将它们按 \(y\) 排序,对每个点找它上面 \(ans\) 内的点,只枚举这范围内的点对来计算答案即可

#include <bits/stdc++.h>
using namespace std;

const int N = 1000005;
const double inf = 1e18;

struct point {
    double x,y;
    bool operator < (const point &b) {
        if(x!=b.x) return x<b.x;
        else return y<b.y;
    }
} p[N];

bool cmp(const point &a, const point &b) {
    return a.y < b.y;
}

double dist2(point a,point b) {
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}

int n;

double solve(int l,int r) {
    if(l==r) {
        return inf;
    }
    else {
        int mid=(l+r)/2;
        double pos=p[mid].x;
        double ans=inf;
        ans=min(ans,solve(l,mid));
        ans=min(ans,solve(mid+1,r));
        int pl=mid,pr=mid+1;
        while(pow(p[pl].x-pos,2)<=ans && pl>=l) --pl;
        ++pl;
        while(pow(p[pr].x-pos,2)<=ans && pr<=r) ++pr;
        --pr;
        vector <point> v;
        for(int i=pl;i<=pr;i++) v.push_back(p[i]);
        sort(v.begin(),v.end(),cmp);
        for(int i=0;i<v.size();i++) {
            for(int j=i+1;j<v.size();j++) {
                if(pow(fabs(v[i].y-v[j].y),2)>ans) break;
                ans=min(ans,dist2(v[i],v[j]));
            }
        }
        return ans;
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++) {
        cin>>p[i].x>>p[i].y;
    }
    sort(p+1,p+n+1);
    printf("%.4lf\n",sqrt(solve(1,n)));
}

猜你喜欢

转载自www.cnblogs.com/mollnn/p/12440925.html
今日推荐