hdu 1007 最近点对问题

       给出二维平面上的n个点,求其中最近的两个点的距离的一半。

   输入包含多组数据,每组数据第一行为n,表示点的个数;接下来n行,每行一个点的坐标。当n为0时表示输入结束,每组数据输出一行,为最近的两个点的距离的一半。

Sample Input

2
0 0
1 1
2
1 1
1 1
3
-1.5 0
0 0
0 1.5
0

Sample Output

0.71
0.00
0.75

题解:

        需要在所有点中寻找最近的两个点对,这时候需要借助二分思想。

        先从一维进行分析,

        使用快排先将x轴排序(从小到大),递归的求左边和右边最小距离的点对将其合并,并不断判断并且选取左边和右边最小距离点对的距离。

        递归求出S1中的最小点对{p1,p2},递归求出S2中最小点对{q1,q2}

        判断d = min{|p1-p2|,|q1-q2|}

        合并后还需判断{p3,q3}是否比d小,这个时候应该遍历出(m-d,m+d)中所有的点,判断是否有比d小的点。

        时间复杂度为:O(nlogn)。

         

        二维情况下,首先根据一维的方法将x轴,使用二分进行判断左右边点对最小值min,选出左右中点对距离最小值min,接下来将y轴进行排序,寻找被选取每个点与其他点满足 (y该点)∈[y-min,y+min],并且判断是否比min小,若小选取该点对距离。(此处最多出现六个满足的点 --鸽巢原理,but 其实使用 (y该点) 做判断也是一样的)。

        



#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>

using namespace std;



struct Note{
    double x,y;
};

Note Point[100002];
int tempPoint[100002];

bool compx(Note a,Note b){return a.x<b.x;}//x轴排序
bool compy(int a,int b){return Point[a].y<Point[b].y;}//y轴排序
double poww(Note a,Note 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?a:b;}
double compute(int start,int endd){
    if(endd - start  == 1){
        return poww(Point[start],Point[endd]);//剩两个点的时候
    }
    if(endd - start == 2){
        return min(poww(Point[start],Point[endd]),min(poww(Point[start+1],Point[start]),poww(Point[start+1],Point[endd])));
    }//剩三个点的时候,这样做是为了减少复杂度

    int mid = (start+endd)>>1;//取中值
    double l_min = compute(start,mid);//递归求左边对点距离最小值
    double r_min = compute(mid+1,endd);//递归求右边对点距离最小值
    double minmin = l_min>r_min?r_min:l_min;
    int cou = 0;
    for(int i = start;i <= endd;i ++){
        if(Point[i].x >= Point[mid].x - minmin&&Point[i].x <= Point[mid].x + minmin){
            tempPoint[cou++] = i;//寻找中点两边小于min的的点,有可能有些点对距离小,且跨越中点
        }
    }
    sort(tempPoint,tempPoint+cou,compy);//对y轴排序

    for(int i = 0;i < cou;i ++){//被选取的y轴的点对进行判断
        int k = 0;
        for(int j = i + 1;j < cou;j++){
            k ++;
            if(Point[tempPoint[j]].y - Point[tempPoint[i]].y > minmin){
                break;
            }
            double temp = poww(Point[tempPoint[i]],Point[tempPoint[j]]);
            minmin = min(temp ,minmin);
            if(k == 6) break;
        }
    }
    return minmin;
}


int main(){
    int n;
    while(scanf("%d",&n)!=EOF){
            if(!n) break;
        for(int i = 0;i < n;i ++){
           scanf("%lf %lf",&Point[i].x,&Point[i].y);
        }
        sort(Point,Point+n,compx);
        double d = compute(0,n-1);
        printf("%.2lf\n",d);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/pack__pack/article/details/80820762