【分治】Quoit Design (HDOJ-1007最近点问题)
2013-05-20 21:40
507 查看
原题链接:点击打开链接
参考了网上的各种资料,算是摸清了这题的思路。
在坐标系中有许多个点,给出点的坐标,要求的是最近两点的距离。
很明显,暴力虽然能得到结果,但是必然超时。因此,使用分治思想。
简单的说,首先,将输入的点按照x轴的大小顺升序。将当前范围内的点均分为左右两个部分。此时,以两部分中间的点为界,当前区域内距离最小的点可能出现两种情况:1是两点被分于同一侧,2是两者分居中线两侧。而如果我们将这种一分为二的步骤继续下去(很显然,这一现象对任一层递归都适用),直到递归的分支中仅仅存在两个或者三个点时向上回溯。
便可以看出:如果最近的两点出现在当前区域的同侧,则两点坐标必然相邻。通过层层将最近点的距离回溯,我们可以找到这种情况的最小点。
然而,回溯时会遇上问题:如果最近点出现在中线两侧,则不能被发现。
为了解决这个问题,我们在每一层回溯的结束之后,对各个点的Y坐标进行一次升序,然后比较各个符合条件的点的距离(此时得出异侧最小值),接着与之前得出的同侧最小值比较,最终得到整个问题的最短距离。
代码如下:
参考了网上的各种资料,算是摸清了这题的思路。
在坐标系中有许多个点,给出点的坐标,要求的是最近两点的距离。
很明显,暴力虽然能得到结果,但是必然超时。因此,使用分治思想。
简单的说,首先,将输入的点按照x轴的大小顺升序。将当前范围内的点均分为左右两个部分。此时,以两部分中间的点为界,当前区域内距离最小的点可能出现两种情况:1是两点被分于同一侧,2是两者分居中线两侧。而如果我们将这种一分为二的步骤继续下去(很显然,这一现象对任一层递归都适用),直到递归的分支中仅仅存在两个或者三个点时向上回溯。
便可以看出:如果最近的两点出现在当前区域的同侧,则两点坐标必然相邻。通过层层将最近点的距离回溯,我们可以找到这种情况的最小点。
然而,回溯时会遇上问题:如果最近点出现在中线两侧,则不能被发现。
为了解决这个问题,我们在每一层回溯的结束之后,对各个点的Y坐标进行一次升序,然后比较各个符合条件的点的距离(此时得出异侧最小值),接着与之前得出的同侧最小值比较,最终得到整个问题的最短距离。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int maxn=5+1e5; class node //创建“点”类型 { public: double x,y; }p1[maxn],p2[maxn]; bool cmpx(node a,node b) //快排的比较函数,用来对类内部的x升序 { return a.x<b.x; } bool cmpy(node a,node b) //对类内部的y升序 { return a.y<b.y; } double dis(node a,node b) //两点距离 { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } double min(double a,double b) { return a>b?b:a; } double mindis(int a,int b) //求最小距离 { if(b-a==1) //当只有两个点时 return dis(p1[a],p1[b]); if(b-a==2) //当有3个点时 return min(min(dis(p1[a], p1[a+1]), dis(p1[a+1], p1[a+2])), dis(p1[a], p1[a+2])); int m=(a+b)>>1; //m为中点 double mini; mini=min(mindis(a,m),mindis(m+1,b)); //递归调用,得出每层位于同侧的最近点距离; int count=0; //找出可能存在有最近点位于中点两边的点,存于p2对象组; for(int i=a;i<=b;i++) { if(fabs(p1[i].x-p1[m].x)<=mini) { p2[count]=p1[i]; count++; } } sort(p2,p2+count,cmpy); //按y坐标再次升序; for(int i=0;i<count;i++) //查找可能存在的最近点; for(int j=i+1;j<count;j++) { if(p2[j].y-p2[i].y>=mini) break; else if(dis(p2[i],p2[j])<mini) mini=dis(p2[i],p2[j]); } return mini; } int main() { int n; while(scanf("%d",&n)!=EOF&&n) { for(int i=0;i<n;i++) scanf("%lf %lf",&p1[i].x,&p1[i].y); sort(p1,p1+n,cmpx); printf("%.2lf\n",mindis(0,n-1)/2); } }
相关文章推荐
- 最近点对问题 POJ 3714 Raid && HDOJ 1007 Quoit Design
- HDU 1007 Quoit Design(最近点对问题:分治)
- 【HDU 1007 】Quoit Design 【分治--最近点对问题】
- HDOJ-1007 Quoit Design(最接近点问题)
- HDU 1007 Quoit Design(分治法求最近点对问题)
- hdu 1007 Quoit Design 求解最近对问题
- 【分治 求最近点对】hdu 1007 Quoit Design
- hdu 1007 zoj 2107 Quoit Design 求平面最近点对 分治法
- hud 1007 Quoit Design 求解平面最近点对的问题
- HDOJ 1007 Quoit Design(最近点对)
- [最近点对]HDOJ 1007 Quoit Design
- hdu 1007 Quoit Design (最近点对问题)
- zoj 2107 Quoit Design(最近点对问题,好好思考,分治)
- HDOJ 1007 Quoit Design(分治)
- hdu 1007 Quoit Design 分治求最近点对
- 杭电ACM OJ 1007 Quoit Design 最近点对 分治 递归
- hdu 1007 Quoit Design 分治求最近点对
- 杭电OJ——1007 Quoit Design(最近点对问题)
- hdu 1007 Quoit Design (最近点对、分治)
- HDU 1007 二维最近点对问题 / 分治