平面分治 平面上的最近点对问题

平面上有\(n\)个点,计算距离最近的两个点之间的距离

将所有点按照横坐标\(x_0\)分成左右两半,那么距离最近的点对一定是下面两种情况中的最小值:
1.两点都属于左半边或者右半边
2.两点一个属于左半边,一个属于右半边
第一种情况可以通过递归来处理,由于计算的是最小值,假设第一情况得到的最小值为\(d\),那么第二种情况可以等价于所有两分属左右两边,并且距离小于\(d\)的点对距离的最小值
设分治时中点横坐标为\(x_0\),则满足条件的点的横坐标取值范围为\(x_0-d<x<x_0+d\),将本次分治涉及到的所有点按照纵坐标从小到大排序,对于每个点,计算它与纵坐标小于等于它本身的点组成的点对距离,设当前点的纵坐标为\(y_p\),则需要考虑纵坐标满足条件\(y_p-d<y<y_p\)的点
所以对于每个点,每次需要检查的另一个点在\(x_0-d<x<x_0+d,y_p-d<y<y_p\)的矩形之内,有结论表示这样的矩形区域内的点不超过6个
所以首先按照横坐标将所有点排序,每次选取中点进行分治并且更新答案(情况1),归并的时候按照纵坐标排序,扫描所有点,找到所有满足要求的点对(不超过6个),更新答案(情况2)
递归深度\(O(\log n)\),每一层操作的时间复杂度\(O(n)\),总的时间复杂度\(O(n\log n)\)

模板题:hdu1007 Quoit Design
平面上有\(n\)个点,环内最多可以套中一个点,计算环的最大半径

环的最大半径为平面上最近点对距离的二分之一

#include<iostream>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<cstring>
#include<string>
#include<sstream>
#include<cmath>
#include<ctime>
#include<algorithm>
#define LL long long
#define PII pair<int,int>
#define PLL pair<LL,LL>
#define PDD pair<double,double>
#define pi acos(-1.0)
#define eps 1e-6
#define lowbit(x) x&(-x)
using namespace std;

const int maxn=100010;
int n;
PDD a[maxn];

bool cmp_y(PDD s1,PDD s2){
    return s1.second<s2.second;
}

double closest_pair(PDD *a,int n){
    if(n<=1) return 10010;
    int m=n/2;
    double x=a[m].first;
    double d=min(closest_pair(a,m),closest_pair(a+m,n-m));
    inplace_merge(a,a+m,a+n,cmp_y);
    vector<PDD> b;
    for(int i=0;i<n;i++){
        if(fabs(a[i].first-x)>=d) continue;
        int l=b.size();
        for(int j=0;j<l;j++){
            double dx=a[i].first-b[l-1-j].first;
            double dy=a[i].second-b[l-1-j].second;
            if(dy>=d) break;
            d=min(d,sqrt(dx*dx+dy*dy));
        }
        b.push_back(a[i]);
    }
    return d;
}

void solve(){
    sort(a,a+n);
    double ans=closest_pair(a,n);
    printf("%.2f\n",ans/2);
}

int main(){
    while(scanf("%d",&n)!=EOF && n){
        for(int i=0;i<n;i++) scanf("%lf %lf",&a[i].first,&a[i].second);
        solve();
    }
    return 0;
}
posted @ 2020-08-07 17:13  fxq1304  阅读(238)  评论(0)    收藏  举报