poj 3714 寻找最近点对

参考自《编程之美》169页,大概原理就是把区间分成两部分,然后递归找每一部分中最近的点对,还有一种情况就是这个点对分属于这两部分,然后选两部分中的部分点枚举即可,取其最小值。


//2013-10-21-17.18
#include <stdio.h>
#include <algorithm>
#include <math.h>
#include <iostream>
const double INF=1e100;

using namespace std;

struct node
{
    double x, y;
    bool flag;
}p[200005], tmp[200005];

bool cmpx(node a, node b)
{
    return a.x < b.x;
}

bool cmpy(node a, node b)
{
    return a.y < b.y;
}

double dis(node a, node b)
{
    return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}

double getans(int l, int r)
{
    double rs = INF;
    if (l == r)
        return rs;
    if (r - 1 == l)
    {
        if (p[l].flag == p[r].flag)
            return rs;
        return dis(p[l], p[r]);
    }
    int mid = (l+r)>>1;
    rs = getans(l, mid);
    rs = min(rs, getans(mid+1, r));
    int cnt = 1;
    for (int i = l; i <= r; i++)
    {
        if (fabs(p[i].x - p[mid].x) <= rs)
            tmp[cnt++] = p[i];
    }
    sort(tmp+1, tmp+cnt, cmpy);

    for (int i = 0; i < cnt; i++)
    {
        for (int j = i+1; j < cnt; j++)
        {
            if (fabs(tmp[i].y-tmp[j].y) >= rs)
                break;
            if (tmp[i].flag != tmp[j].flag)
                rs = min(rs, dis(tmp[i], tmp[j]));
        }
    }
    return rs;
}

int main()
{
    int t, n;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d", &n);
        int i = 1;
        for (; i <= n; i++)
        {
            scanf("%lf %lf", &p[i].x, &p[i].y);
            p[i].flag = false;
        }
        n <<= 1;
        for (; i <= n; i++)
        {
            scanf("%lf %lf", &p[i].x, &p[i].y);
            p[i].flag = true;
        }
        sort(p+1, p+n+1, cmpx);
        printf("%.3lf\n", getans(1, n));
    }
    return 0;
}


posted @ 2013-10-21 18:13  xindoo  阅读(195)  评论(0编辑  收藏  举报