【分治】Quoit Design (HDOJ-1007最近点问题)

原题链接:点击打开链接

参考了网上的各种资料,算是摸清了这题的思路。

在坐标系中有许多个点,给出点的坐标,要求的是最近两点的距离。

很明显,暴力虽然能得到结果,但是必然超时。因此,使用分治思想。

简单的说,首先,将输入的点按照x轴的大小顺升序。将当前范围内的点均分为左右两个部分。此时,以两部分中间的点为界,当前区域内距离最小的点可能出现两种情况:1是两点被分于同一侧,2是两者分居中线两侧。而如果我们将这种一分为二的步骤继续下去(很显然,这一现象对任一层递归都适用),直到递归的分支中仅仅存在两个或者三个点时向上回溯。

便可以看出:如果最近的两点出现在当前区域的同侧,则两点坐标必然相邻。通过层层将最近点的距离回溯,我们可以找到这种情况的最小点。

然而,回溯时会遇上问题:如果最近点出现在中线两侧,则不能被发现。

为了解决这个问题,我们在每一层回溯的结束之后,对各个点的Y坐标进行一次升序,然后比较各个符合条件的点的距离(此时得出异侧最小值),接着与之前得出的同侧最小值比较,最终得到整个问题的最短距离。

代码如下:

#include
#include
#include
#include
#include
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.xb?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=mini)
                break;
            else if(dis(p2[i],p2[j])


你可能感兴趣的:(【分治】Quoit Design (HDOJ-1007最近点问题))