zoukankan      html  css  js  c++  java
  • 最近点对-分治

    题目描述
      给出二维平面上的n个点,求其中最近的两个点的距离的一半。
      输入包含多组数据,每组数据第一行为n,表示点的个数;接下来n行,每行一个点的坐标。当n为0时表示输入结束,每组数据输出一行,为最近的两个点的距离的一半。
      输入样例:
        2
        0 0
        1 1
        2
        1 1
        1 1
        3
        -1.5 0
        0 0
        0 1.5
        0
      输出样例:
        0.71
        0.00
        0.75
    题目解析:
      采用分治的思想,把n个点按照x坐标进行排序,以坐标mid为界限分成左右两个部分,对左右两个部分分别求最近点对的距离,然后进行合并。对于两个部分求得的最近距离d,合并过程中应当检查宽为2d的带状区间是否有两个点分属于两个集合而且距离小于d,最多可能有n个点,合并时间最坏情况下是O(n^2).但是,左边和右边中的点具有以下稀疏的性质,对于左边中的任意一点,右边的点必定落在一个d*2d的矩形中,且最多只需检查6个点(鸽巢原理),这样,先将带状区间的点按照y坐标进行排序,然后线性扫描,这样合并的时间复杂度为O(nlogn)。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    double MAX=1e10; //定义的最大距离,以在只有一个点的时返回无穷大
    int a,b;   //用来记录下标,与题无关
    struct Node{
        double x,y;
        int key;   //关键码,可有可无,与ab有关
    };
    
    Node ar[100005],br[100005];
    
    bool cmpx(Node a,Node b){return a.x<b.x;}  //x坐标升序
    bool cmpy(Node a,Node b){return a.y<b.y;}  //y坐标升序
    double min(double a,double b){return a<b?a:b;}  //返回最小值
    double dis(Node a,Node b){return sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2));}  //返回点与点之间的距离
    
    double cal(int s,int e)  //s、e用来表示当前处理的数组中的下标位置
    {
        int mid,i,j,tail=0;   //mid表示数组中间的位置下标 ,tail作为计数变量,是用来br数组存储标号的
        double d;   //d表示点对之间的距离
        if(s==e) return MAX;   //如果只有一个点
        mid=(s+e)/2;
        d=min(cal(s,mid),cal(mid+1,e));  //递归求出左右两边的最小距离
          //下面是求是否存在左边的点到右边某点的距离小于d的点,或者是否存在在右边的点到左边某点的距离小于d的点,若是存在,必定处于一个d*2d的矩形中
        for(i=mid;i>=s&&ar[mid].x-ar[i].x<d;i--){   //筛选左边的点,在中间位置左侧d以内的点
            br[tail++]=ar[i];
        }
    
        for(i=mid+1;i<e&&ar[i].x-ar[mid].x<d;i++)    //同上,筛选右边的点
        {
            br[tail++]=ar[i];
        }
        sort(br,br+tail,cmpy);                      //对矩形内的点按照y坐标进行排序
        for(i=0;i<tail;i++){              //枚举矩形内点对之间的距离                   
            for(j=i+1;j<tail&&br[j].y-br[i].y<d;j++){
                if(d>dis(br[i],br[j])){           //更新点的值
                    //a=min(br[i].key,br[j].key);
                    //b=br[i].key+br[j].key-a;
                    d=min(d,dis(br[i],br[j]));   
                }
            }
        }
        return d;                     //返回最小的点对之间的距离
    }
    
    int main()
    {
    
        int n;
        while(cin>>n&&n){
            for(int i=0;i<n;i++){
                ar[i].key=i+1;               //关键码赋值
                scanf("%lf %lf",&ar[i].x,&ar[i].y);
            }
            sort(ar,ar+n,cmpx);            //按x对ar排序
            double d=cal(0,n);                       
            printf("%.2lf
    ",d/2.0);
        }
        return 0;
    }
    
  • 相关阅读:
    Entity SQL 初入
    ObjectQuery查询及方法
    Entity Framework 的事务 DbTransaction
    Construct Binary Tree from Preorder and Inorder Traversal
    Reverse Linked List
    Best Time to Buy and Sell Stock
    Remove Duplicates from Sorted Array II
    Reverse Integer
    Implement Stack using Queues
    C++中const限定符的应用
  • 原文地址:https://www.cnblogs.com/yifeichongtian/p/10083383.html
Copyright © 2011-2022 走看看