HDU-1007 Quoit Design

题目大意:给你n个点,代表toy,求一个使得可以套住一个toy且只能套住一个toy的环的最大半径。

解法:只需要求出所有点的最近点对的长度就可以解决了。但是如何求最近点对?
最容易想到的就是暴力枚举所有点对,求出最小长度,然后就可以得到结果。但是复杂度为O(n^2)而这题n的范围是100000,必然不能通过。所以可以使用分治来解决这题。
分治解决这个问题的复杂度为O(nlognlogn),所以是比较适合的。

知道怎么做就可以上代码了。
我直接跟这kuangbin的模板敲了一发。

//time   memery
//1060ms 4572k
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define INF 1e18
const int maxn = 100000 + 10;
typedef struct{
    double x, y;
}Coord;
Coord p[maxn], tmp[maxn];
bool cmp1(Coord a, Coord b){
    if(a.x != b.x)
        return a.x < b.x;
    else
        return a.y < b.y;
}
bool cmp2(Coord a, Coord b){
    if(a.y != b.y)
        return a.y < b.y;
    else
        return a.x < b.x;
}
inline double f(int x){
    return (x > 0 ? x : -x);
}
inline double Min(double a, double b){
    return (a < b ? a : b);
}
inline double Dist(Coord a, Coord b){
    return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
double Cal_Closest(int left, int right){
    double d = INF;

    if(left == right){
        return d;
    }
    if(left + 1 == right){
        return Dist(p[left], p[right]);
    }

    int mid = (left + right) >> 1;
    double d1 = Cal_Closest(left, mid);
    double d2 = Cal_Closest(mid + 1, right);
    d = Min(d1, d2);

    int k = 0;
    for(int i = left; i <= right; ++i){
        if(f(p[mid].x - p[i].x) <= d){
            tmp[k++] = p[i];
        }
    }
    sort(tmp, tmp + k, cmp2);

    for(int i = 0; i < k; ++i){
        for(int j = i + 1; j < k && tmp[j].y - tmp[i].y < d; ++j){
            d = Min(d, Dist(tmp[i], tmp[j]));
        }
    }

    return d;
}
int main()
{
    int n;
    while(scanf("%d", &n) && n){
        memset(p, 0, sizeof(p));
        for(int i = 0; i < n; ++i){
            scanf("%lf%lf", &p[i].x, &p[i].y);
        }
        sort(p, p + n, cmp1);

        printf("%.2lf\n", Cal_Closest(0, n - 1) / 2);
    }
    return 0;
}
posted @ 2016-05-20 10:15  _Wilbert  阅读(112)  评论(0编辑  收藏  举报