bzoj3053 The Closest M Points [kd-tree]

Description:
k k 维空间询问第m近点对。


Solution:
kdtree k d − t r e e 裸题。


#include <bits/stdc++.h>
using namespace std;
const int N = 305;
struct P {
    double x, y;
    P() {} 
    P(double _x, double _y) : x(_x), y(_y) {}
    P friend operator + (const P &a, const P &b) {
        return P(a.x + b.x, a.y + b.y);
    }
    P friend operator - (const P &a, const P &b) {
        return P(a.x - b.x, a.y - b.y);
    }
    P friend operator * (const P &a, double b) {
        return P(a.x * b, a.y * b);
    }
    double friend operator * (const P &a, const P &b) {
        return a.x * b.y - a.y * b.x;
    }
} p[N], a[N];
struct L {
    P p, v;
    double ang;
    L() {}
    L(P _p, P _v) : p(_p), v(_v) { ang = atan2(v.y, v.x); }
} l[N], q[N];
int n, m, head, tail;
double ans = 1e9;
P inter(L a, L b) {       
    P u = a.p - b.p;  
    double d = (b.v * u) / (a.v * b.v);
    return a.p + a.v * d;
}
bool left(L a, P b) {
    return (b - a.p) * a.v < 0;
}
bool cmp(L a, L b) {
    return a.ang == b.ang ? !left(a, b.p) : a.ang < b.ang;
}
int main() {
    scanf("%d", &n);
    ++n;
    for(int i = 2; i <= n; ++i) {
        scanf("%lf", &p[i].x);
    }
    for(int i = 2; i <= n; ++i) {
        scanf("%lf", &p[i].y);
    }
    p[1].x = p[2].x;
    p[1].y = 1000001;
    p[n + 1].x = p[n].x;
    p[n + 1].y = 1000001;
    for(int i = 1; i <= n; ++i) {
        l[i] = L(p[i], p[i + 1] - p[i]);
    }
    sort(l + 1, l + n + 1, cmp);
    l[++m] = l[1];
    for(int i = 2; i <= n; ++i) {
        if(l[i].ang != l[m].ang) {
            l[++m] = l[i];
        }
    }
    q[++tail] = l[1];
    q[++tail] = l[2];
    for(int i = 3; i <= m; ++i) {
        while(head < tail && !left(l[i], inter(q[tail], q[tail - 1]))) {
            --tail;
        }
        while(head < tail && !left(l[i], inter(q[head], q[head + 1]))) {
            ++head;
        }
        q[++tail] = l[i];
    } 
    while(head < tail && !left(q[tail], inter(q[head], q[head + 1]))) {
        ++head;
    }
    while(head < tail && !left(q[head], inter(q[tail], q[tail - 1]))) {
        --tail;
    }
    m = 0;
    for(int i = head; i < tail; ++i) {
        a[++m] = inter(q[i], q[i + 1]);
    }
    for(int i = 1; i <= n; ++i) {
        P t;
        t.x = 0;
        t.y = 1;
        for(int j = 1; j < m; ++j) {
            if(a[j].x <= p[i].x && a[j + 1].x >= p[i].x) {
                P tmp = inter(L(p[i], t), L(a[j], a[j] - a[j + 1]));
                ans = min(ans, fabs(tmp.y - p[i].y));
            }
        }
    }
    for(int i = 1; i <= m; ++i) {
        P t;
        t.x = 0;
        t.y = 1;
        for(int j = 1; j < n; ++j) {
            if(p[j].x <= a[i].x && p[j + 1].x >= a[i].x) {
                P tmp = inter(L(a[i], t), L(p[j], p[j] - p[j + 1]));
                ans = min(ans, fabs(a[i].y - tmp.y));
            }
        } 
    }
    printf("%.3f\n", ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值