• 【书上讲解】平面上最近点对问题


    给你二维平面上的n个点,让你求出其中最近的点对。

    【题解】

    这是一个分治的问题。 可以这样做: 首先将n个点按照x升序排。 然后将l..r这个区间内的点分成 l..mid和mid+1..r两个部分递归求解。 分别求出这两段里面的点的最近点对的距离d1和d2 然后令d = min(d1,d2) 这是最后答案的点都在其中一边的情况。 现在考虑最后答案的点对分别在左区间p1和右区间p2的情况。 首先可以将左区间和右区间中点的横坐标和分割线距离超过d的点去掉。 然后对于每一个p1,在其右侧画一个长d,高2d的矩形。 就会发现那个矩形内最多只会有6个右区间中的点(鸽巢原理) 所以我们只需要将l..r这个区间内的点按照y轴升序排一下序就好。 然后对于每个点(x,y)检查y坐标的范围在(y-d,y+d)的其他点就好. 但这样排序的话,时间复杂度是n*logn*logn级别的。 我们可以在进行答案的合并的时候,顺便对每个子区间做一下归并排序(按照y轴). 然后归并排序的时候,对于左区间的点,顺便遍历和它的y坐标差的绝对值小于d的其他点即可 这样时间复杂就是n*logn级别的了

    【代码】

    #include <cstdio>
    #include <cmath>
    using namespace std;
    
    const int N = 1e5;
    const int oo = 1e9;
    
    struct abc{
        int x,y;
    };
    
    int n;
    abc a[N+10];
    abc b[N+10];
    
    int sqr(int x){return x*x;}
    
    int dis(abc a,abc b){
        return sqr(a.x-b.x)+sqr(a.y-b.y);
    }
    
    int min(int x,int y){
        if (x<y) return x;else return y;
    }
    
    int divide(int l,int r){
        if (l>=r) return oo;
        int mid = (l+r)>>1;abc mp = a[mid];
        int d = divide(l,mid);d = min(d,divide(mid+1,r));
        int i = l,j = mid + 1,k = l;
        while (i<=mid || j<=r){
            while (j<=r && (i>mid || a[j].y<=a[i].y)) b[k++] = a[j++];
            if (i<=mid && mp.x-a[i].x<d){//a[i]是分割线左边的点
                //此时a[mid+1..j-1]全都小于等于a[i]的纵坐标
                //a[j..r]全都大于a[i]的纵坐标。(且这两段的点都是分割线右边的点)
                for (int l = j-1;l>=mid+1;l--){
                    if (sqr(a[i].y-a[l].y)>d) break;
                    int temp = dis(a[l],a[i]);
                    d = min(temp,d);
                }
                for (int l = j;l<=r;l++){
                    if (sqr(a[l].y-a[i].y)>d) break;
                    int temp = dis(a[l],a[i]);
                    d = min(temp,d);
                }
            }
            if (i<=mid) b[k++] = a[i++];
        }
        for (int i = l;i<= r;i++) a[i] = b[i];
        return d;
    }
    
    void _swap(abc *x,abc *y){
        abc t = *x;
        *x = *y;
        *y = t;
    }
    
    void kp(abc a[],int l,int r){
        abc temp = a[l];
        int i = l,j = r+1;
        while(true){
            while (a[++i].x<temp.x && i<r);
            while (a[--j].x>temp.x);
            if (i>=j) break;
            _swap(&a[i],&a[j]);
        }
        a[l] = a[j];
        a[j] = temp;
        if (l<j) kp(a,l,j-1);
        if (j<r) kp(a,j+1,r);
    }
    
    int main(){
        scanf("%d",&n);
        for (int i = 1;i <= n;i++) scanf("%d%d",&a[i].x,&a[i].y);
        kp(a,1,n);
        double ans = sqrt(1.0*divide(1,n));
        printf("%.3f
    ",ans);
        return 0;
    }
    
    
  • 相关阅读:
    is as运算符
    继承,多态
    封装等
    面向对象
    在JDBC中使用带参数的SQL语句
    我的程序库:HiCSDB
    我的程序库:HiCSUtil
    Java中,将ResultSet映射为对象和队列及其他辅助函数
    Java版的对象关系映射实现
    Java中的基本数据类型转换
  • 原文地址:https://www.cnblogs.com/AWCXV/p/11622575.html
Copyright © 2020-2023  润新知