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


    平面上有(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(nlog 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
    ",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;
    }
    
  • 相关阅读:
    Log4Net记录到MySql
    创建快照
    grep的用法(CentOS7)及有关正则表达式的使用
    samba
    mkdir
    raid0和raid5的 实验过程
    route
    source和sh执行脚本时的差异
    echo命令的简单用法和实例
    smbpasswd和pdbedit
  • 原文地址:https://www.cnblogs.com/fxq1304/p/13454031.html
Copyright © 2020-2023  润新知