计算几何--分治--最近对 hdu1007

分治

关键在于,最后合并的时候,取x = ps[mid].x,往左右划x - mindis,x + mindis的线,最近对还可能出现在这个带状区域中

虽然可以对x左边的点在右边的区域找,但是十分不好找到他对应的点,还不如全部放在一起,按y排序,从下向上找更好。

#include <iostream>

#include <cstdio>

#include <algorithm>

#include <cmath>

#include <vector>

using namespace std;

const int maxn =1e5 + 5;


struct point{

    double x,y;

    bool operator < (constpoint &a) const{

        return x < a.x || (x == a.x &&y < a.y);

    }

}ps[maxn],tmp[maxn];

int n;

double mindis;

bool cmp(constpoint &a,constpoint &b){

    return a.y < b.y;

}

double getdis(point &p1,point &p2)

{

    return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);

}

void merge(int l,int mid,int r)//如果从左边对右边求的话,不好找,还是把区间的全部放在一起按y排序,从下往上数6个更好

{

    double x = ps[mid].x;

    vector<point> v;

    for (int i = l; i <= r; i ++) {

        if(x - mindis <=ps[i].x && ps[i].x <= x + mindis) v.push_back(ps[i]);

    }

    sort(v.begin(),v.end(),cmp);


    for (int i =0 ; i < v.size(); i ++) {

        for (int j =1; j <= 6 && i + j < v.size(); j ++) {

            mindis = min(mindis,getdis(v[i], v[i +j]));

        }

    }

}

void closet_point_pair(int l,int r)

{

    if(r - l == 1){// 2 points

        mindis = min(mindis,getdis(ps[l],ps[l + 1]));

    }

    else if(r - l ==2){// 3 points

        mindis = min(mindis,getdis(ps[l],ps[l + 1]));

        mindis = min(mindis,getdis(ps[l],ps[r]));

        mindis = min(mindis,getdis(ps[r -1], ps[r]));

    }

    else{

        int mid = (l + r) / 2;

        closet_point_pair(l, mid);

        closet_point_pair(mid + 1, r);

        merge(l,mid,r);

    }

}

int main()

{

    while (scanf("%d",&n) !=EOF) {

        if(n ==0) break;

        for (int i =0; i < n; i ++) {

            scanf("%lf%lf",&ps[i].x,&ps[i].y);

        }

        sort(ps,ps +n);

        mindis = getdis(ps[0],ps[1]);

        closet_point_pair(0,n -1);

        printf("%.2lf\n",sqrt(mindis) /2);

    }

    return 0;

}



猜你喜欢

转载自blog.csdn.net/sm_545/article/details/80007334
今日推荐