[最近点对]HDOJ 1007 Quoit Design

来源:互联网 发布:java吃豆豆游戏 编辑:程序博客网 时间:2024/04/28 02:38

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1007

 

题目大意:在平面上有N个点,求出两点之间距离的最小值/2,就是结果.

算法详细介绍:http://blog.csdn.net/guyulongcs/article/details/6841550,这里讲得很清楚。

也就是一个很裸的算法题吧,要求用O(nlogn)的算法求出最近点对,翻了翻算法导论,看完了上面用分治法解答,自己实现的时候有几个点需要注意:

1.如果每次递归求解的时候,开出新的数组来保存,集合Sy的划分,那么一定会MLE,看了别人的代码后,发现可以用先分解,再归并,那么只需要增加一个辅助数组,解决了MLE的问题。

2.关于如何分解原问题,开始用的是算法导论上说的,以Sx的中间点的横坐标来划分,分解成<=Sx[mid].x的和>=Sx[mid].x的,这样只用一个辅助数组的方法不适用,因为可能有很多点的横坐标相同,再想到分解成<=Sx[mid].x的和>Sx[mid].x的,这样也行不通,因为可能导致>Sx[mid].x的部分没有点,在某算法模板上看到,可以按照元素在最开始的Sx中的顺序,为每个元素增加一个域index来记录该元素在Sx中处于什么位置,这样就可以把问题分解成<=Sx[mid].index的和>Sx[mid].index的,没有问题。

3.总结最近点对的整体算法框架:

     (1)预处理,用两个集合Sx,Sy保存所有的点,不同的是Sx按照x升序排列,Sy按照y升序排列。

     (2)递归求解:边界条件为,当前待处理点集的点的个数<=3

                                递归框架为,分解Sx,分解Sy,并保证Sy的两个子集按y的升序排列,递归求解,用归并将Sy还原到没分解以前,合并子问题。

4.关于合并子问题的正确性证明还有待研究。

 

AC代码:

#include<iostream>#include<cstring>#include<cstdio>#include<cmath>#include<algorithm>using namespace std;const int MAXN = 100010;const double inf = 10e100;#define SQL(x) (x)*(x)struct Point{  double x,y;  int index;     }sx[MAXN],sy[MAXN],st[MAXN];bool x_cmp(const Point &p1,const Point &p2){     return p1.x<p2.x;}bool y_cmp(const Point &p1,const Point &p2){     return p1.y<p2.y;}double dis(Point p1,Point p2){       return sqrt(SQL(p1.x-p2.x)+SQL(p1.y-p2.y));}double merge(Point sy[],Point st[],int l,int r,double dist,double L){       int Len = 0;       for(int i=l;i<=r;i++)       {           if(sy[i].x>(L-dist)&&sy[i].x<(L+dist))st[Len++]=sy[i];       }              for(int i=0;i<Len;i++)       {           for(int j=i+1;j<Len&&j<i+8;j++)           {               dist = min(dist,dis(st[i],st[j]));           }       }       return dist;}double solve(Point sx[],Point sy[],Point st[],int l,int r){       if(r==l)return inf;       else if(r-l==1)return dis(sx[l],sx[r]);       else if(r-l==2)       {            double x1 = dis(sx[l],sx[l+1]);            double x2 = dis(sx[l],sx[r]);            double x3 = dis(sx[l+1],sx[r]);            x1 = min(x1,x2);            x1 = min(x1,x3);            return x1;       }       else       {           int m = (l+r)>>1,i,j,k;           double L = sx[m].x, dist;           for(i=l,j=l,k=m+1;i<=r;)           {               if(sy[i].index<=sx[m].index)st[j++]=sy[i++];               else st[k++]=sy[i++];           }           //printf("%d %d ~~~\n",j,k);           for(i=l;i<=r;i++)sy[i]=st[i];//,printf("%.2lf %.2lf\n",st[i].x,st[i].y);system("pause");           double p = solve(sx,sy,st,l,m),q = solve(sx,sy,st,m+1,r);           //printf("%.2lf  %.2lf\n",p,q);system("pause");           dist = min(p,q);           for(i=l,j=l,k=m+1;j<=m&&k<=r;)           {               if(sy[j].y<sy[k].y)st[i++]=sy[j++];               else if(sy[j].y>sy[k].y)st[i++]=sy[k++];               else               {                   if(sy[j].index<sy[k].index)st[i++]=sy[j++];                   else st[i++] = sy[k++];               }           }           while(j<=m)st[i++]=sy[j++];           while(k<=r)st[i++]=sy[k++];           for(i=l;i<=r;i++)sy[i]=st[i];           //system("pause");           dist = merge(sy,st,l,r,dist,L);            //printf("%.2lf\n",dist);           return dist;       }}int main(){    int n;    //freopen("in.txt","r",stdin);    //freopen("out2.txt","w",stdout);    while(scanf("%d",&n),n)    {        for(int i=0;i<n;i++)        scanf("%lf%lf",&sx[i].x,&sx[i].y);        stable_sort(sx,sx+n,x_cmp);        for(int i=0;i<n;i++)        sx[i].index = i,sy[i]=sx[i];        stable_sort(sy,sy+n,y_cmp);        //for(int i=0;i<n;i++)printf("%.2lf %.2lf %d\n",sx[i].x,sx[i].y,sx[i].index);        //printf("\n");        //for(int i=0;i<n;i++)printf("%.2lf %.2lf %d\n",sy[i].x,sy[i].y,sy[i].index);        printf("%.2lf\n",solve(sx,sy,st,0,n-1)/2);    }}


 

原创粉丝点击