HDU 1007 Quoit Design 最近点对 分治法

来源:互联网 发布:中国商业源码网 编辑:程序博客网 时间:2024/05/20 06:07

题意:有N个玩具,给出这些玩具的点的坐标。求出一个半径最大的圆环,使这个圆环至多能套进一个玩具。

思路:圆环至多能套进一个玩具,当且仅当圆环的直径小于等于任意两点的距离。这样就转化成了最近点对问题。

           对于最近点对问题,同样是用分治法进行处理。

           首先,对所有点按照x坐标从小到大进行排序,按照x坐标将点分成两半。

           同样,分治后有下面两种情况:

           1.p,q两点位于左半边或者位于右半边,这种情况可以递归处理。

           2.p,q两点一个位于左半边,一个位于右半边。这是我们重点讨论情况。

           对于第二种情况,虽然我们找到了一个我们待处理的点的性质:跨过中点线,但是这个好像没啥用。

           所以,关于最近点对的分治法,是和前面不同的。前面的几种分治中,第二种情况的处理是不依赖于第一种情况的。但是在最近点对的分治法中,第二种情况的处理要利用第一种情况得到的最小值来约束检查点的范围。

           设在第一种情况下,我们求得的最近距离为d。那对于第二种情况,我们要检查的点的范围x0- d < x < x0 + d ,因为在剩余范围的点的距离必然大于d,不需要再判断。

           同样,我们也可以约束y坐标。对于每个点,我们只检查它下面的的点,即范围 y <= y0 。同样利用距离d,我们可以将检查点的范围缩小到:y0- d <= y <= y0.

           可以证明,在x0- d < x < x0 + d 和y0- d <= y <= y0 内的点至多有5个。

           为了更高效的处理第二种情况,我们要把所有待考虑的点按照y坐标进行排序,因此我们递归处理的时候,按照y坐标进行归并排序。

注意:网上很多最近点对的算法,会在算法的中间会直接对y坐标进行排序,这样会潜在的提高算法的复杂度。

           代码中还有一个技巧就是传指针,我们就能递归时直接传入递增的地址,让下标从0开始,在编程是十分方便的。

代码如下:

#include <cstdio>#include <algorithm>#include <utility>#include <cmath>using namespace std;const int MAX = 100010;struct point{    double x,y;    point(){}    point(double xx, double yy):x(xx),y(yy){}    bool operator < (const point & rhs) const{        return x  < rhs.x;    }};bool cmp(const point & lhs, const point & rhs){    return lhs.y < rhs.y;}point p[MAX],b[MAX];int N,sz;double solve(point * a, int n){    if(n <= 1) return 0x6f6f6f6f;    int m = n / 2;    double x = a[m].x;    double d = min(solve(a,m),solve(a+m,n-m));    inplace_merge(a,a+m,a+n,cmp);    sz = 0;    for(int i = 0; i < n; ++i){        if(fabs(a[i].x - x) >= d) continue;        for(int j = 0; j < sz; ++j){            double dx = a[i].x - b[sz - j - 1].x;            double dy = a[i].y - b[sz - j - 1].y;            if(dy >= d) break;            d = min(d,sqrt(dx * dx + dy * dy));        }        b[sz++] = a[i];    }    return d;}int main(void){    //freopen("input.txt","r",stdin);    while(scanf("%d",&N),N){        for(int i = 0; i < N; ++i)            scanf("%lf%lf",&p[i].x,&p[i].y);        sort(p,p + N);        printf("%.2f\n",solve(p,N) / 2.0);    }    return 0;}




0 0
原创粉丝点击