其他分享
首页 > 其他分享> > P1429 平面最近点对

P1429 平面最近点对

作者:互联网

感谢所有AC

传送门

思路

       分治能解决这个题目吗?乍一看并不可行,如果把所有点中分,取左部分的最小距离和右部分的最小距离来作为所有点的最小距离,这样的分治策略明显是不正确的,因为这样就忽视了左部分和右部分中的点形成的点对,即一些跨界的距离可能是最短距离。这是分治所遇到的问题,如果能够解决这个问题,那么分治将是一个很好的解法,时间上也是很可观的。

       怎么处理跨界点对?不妨把思路放简单一点,我直接把所有跨界点对的距离求出来,然后用这些距离来更新答案不就ok了?这样的时间复杂度是 n2 的,是否有优化的空间?由于答案出自三个部分,左区间点对,右区间点对,跨界点对。如果在先知道了左右区间点对的最短距离后,似乎可以用剪枝的思想来优化跨界点对的求解。

       假如目前左右区间点对最优解为 len ,那么只要左区间内的点对跟中分线的垂直距离大于等于 len ,那么他就不可能是最优解,右区间同理。这样就筛除了很大数量的点,接下来,把可能是最优解的点存进数组中,然后 n2 地逐个计算距离并更新答案。这样就可以实现最优解的实现了。

代码

#include <iostream>
#include<algorithm>
#include<cmath>
#define maxn 200007
using namespace std;
struct node {
    double x, y;
    bool operator<(const node& A) {
        if (x != A.x)return x < A.x;
        return y < A.y;
    }
}point[maxn];
int temp[maxn << 1], n;
double dis(node a, node b)
{
    double x = (a.x - b.x) * (a.x - b.x);
    double y = (a.y - b.y) * (a.y - b.y);
    return sqrt(x + y);
}
double daq(int l, int r)
{
    if (l == r)
        return 1e9;
    //由于是计算点对距离,需要如下的特判来提供距离
    if (l + 1 == r)
        return dis(point[l], point[r]);
    int m = l + r >> 1, k = 0;
    //先找出左右区间点对最优解
    double d = min(daq(l, m), daq(m + 1, r));
    //第一次剪枝
    for (int i = l; i <= r; i++)
        if (fabs(point[i].x - point[m].x) < d)
            temp[++k] = i;
    //计算点对距离时,再次剪枝优化复杂度
    for (int i = 1; i < k; i++)
        for (int j = i + 1; j <= k && fabs(point[temp[i]].x - point[temp[j]].x) < d; j++)
            d = min(d, dis(point[temp[i]], point[temp[j]]));
    return d;
}
int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> point[i].x >> point[i].y;
    sort(point + 1, point + n + 1);
    printf("%.4lf", daq(1, n));
    return 0;
}

 

标签:跨界点,point,距离,最近,平面,区间,P1429,最优,include
来源: https://www.cnblogs.com/xqk0225/p/16147282.html