hdu1007 Quoit Design

来源:互联网 发布:常州罗盘网络智能科技 编辑:程序博客网 时间:2024/05/21 19:27

        首先说一下这题的题意,题意很简单,就是给出平面上N个点的横坐标与纵坐标,求最近的两点的距离(2<=N<=1000000)。

        这题首先很容易想到朴素的方法:分别枚举两个点,通过比较找出其中的最小值,这是O(N^2)的算法,对于N<=1000000的数据范围,是肯定会超时的,这就要我们想其他方法。

        那么现在介绍的就是一个高效求最近点对的方法。一看这数据范围,就会想到这应该是一个O(nlogn)的算法。那么首先想到的应该就是分治的思想,我们对于x轴,将平面上的点分成两部分,如下图所示:


        我们可以很容易想到,最近点对的分布有三种可能性,第一种就是两个点均在mid的左边,第二种就是两个点均在mid的右边,第三种情况就是这两个点分别分布在mid的左边和右边。第一种情况和第二种情况的最近点,可以通过比较相邻的点来获得,我们记得到的最近点的距离为d。接下来最困难的部分就是合并了,我们知道,两个点坐标的距离公式是(x1-x2)^2-(y1-y2)^2,也就是说,这两个点横坐标的距离和纵坐标的距离都要小于d,这样这两个点才有可能是最近点对,否则不可能为最近点对,这样我们就进行了一个类似于剪枝的操作,算法的复杂度也就在这个处理上由O(n^2)降到了O(n*logn*logn),接下来只需要通过递归来一层层推回去即可。

接下来附上代码:

#include <stdio.h>#include <stdlib.h>#include <math.h>#include <algorithm>#define maxnum 2147483647using namespace std;int n;typedef struct{    double x,y;} atp;atp a[100005];double mini(double x,double y){    return x<y?x:y;}bool cmp1(atp a,atp b){    return a.x<b.x;}bool cmp2(atp a,atp b){    return a.y<b.y;}double work(int f,int r){    int mid,i,j,ff,rr;    double ans;   //注意类型1.不要使用int类型 2.float精度不够,话说float精度有这么低么。。。郁闷    if(f==r) return maxnum;    else    {        if((r-f)==1) return ((a[r].x-a[f].x)*(a[r].x-a[f].x)+(a[r].y-a[f].y)*(a[r].y-a[f].y));  //递归的结束条件是要最先考虑的        else        {            mid=(f+r)/2;            ans=mini(work(f,mid),work(mid+1,r));            //找到y符合的区间            for(i=mid;i>=f;i--)                if(a[mid].y-a[i].y>ans)                    break;            for(j=mid+1;j<=r;j++)                if(a[j].y-a[mid].y>ans)                    break;            ff=i+1;rr=j-1;            sort(a+ff,a+rr+1,cmp1);  //对y符合的区间以x为关键字进行排序            //筛选符合要求的x区间,并对其进行最终确认            for(i=ff;i<rr;i++)            {                for(j=i+1;j<=rr && a[j].x-a[i].x<ans;j++)                {                    ans=mini(ans,(a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));                }            }            return ans;        }    }}int main(){    int i;    double ans;    while(scanf("%d",&n)!=EOF)    {        if(n==0) break;        for(i=1;i<=n;i++)            scanf("%lf%lf",&a[i].x,&a[i].y);        sort(a+1,a+n+1,cmp2); //c++ sort 的规则要注意        ans=work(1,n);        printf("%.2lf\n",sqrt(ans)/2);    }    return 0;}


       

0 0
原创粉丝点击