平面最近点对

P1429 平面最近点对(加强版)

题目描述

给定平面上n个点,找出其中的一对点的距离,使得在这n个点的所有点对中,该距离为所有点对中最小的

输入格式

第一行:n;2≤n≤200000

接下来n行:每行两个实数:x y,表示一个点的行坐标和列坐标,中间用一个空格隔开。

输出格式

仅一行,一个实数,表示最短距离,精确到小数点后面4位。

输入输出样例

输入 #1
3
1 1
1 2
2 2
输出 #1
1.0000

说明/提示

0<=x,y<=10^9

思路:运用分治思想,对于n个点,可以分成T(n/2)+T(n/2)的规模,分界线是x坐标的中位数,

假设左边点集合为s1, 右边点集合为s2,那么最小值存在于以下三种情况中。

1.s1中任意两点距离的最小距离

2.s2中任意两点距离的最小距离

3.s1中的点到s2中的点的距离的最小距离

前两部分可以一直分治到底。

第三部分

对于左边每一个点,右边和他产生距离更小的点只能存在于

2d*d的矩形中,而对于2d/3*d/2的矩形,只可能存在一个点,所以点数最多不超过6个

这就使每一层的时间降到O(n),所以总复杂度为O(nlogn)
————————————————
原文链接:https://blog.csdn.net/du_lun/article/details/83344425

#pragma GCC optimize(2)
#pragma GCC optimize(3, "Ofast", "inline")

#include<bits/stdc++.h>//平面最近点对

#define ll long long
#define inf 0x3f3f3f3f

using namespace std;
const double INF = 1e18;
const double eps = 1e-10;

struct node {
    double x, y;

    bool operator<(const node &a) const {
        return x < a.x;
    }
} s[200010], t[200010];

bool cmp(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 cdq(int l, int r) {
    double d = INF;
    if (l >= r)return d;
    int mid = (l + r) >> 1;
    d = min(d, cdq(l, mid));
    d = min(d, cdq(mid + 1, r));
    int cnt = 0;
    for (int i = l; i <= r; i++) {
        if (fabs(s[i].x - s[mid].x) <= d)
            t[++cnt] = s[i];
    }
    sort(t + 1, t + 1 + cnt, cmp);
    for (int i = 1; i <= cnt; i++) {
        for (int j = i + 1; j <= cnt && fabs(t[i].y - t[j].y) <= d; j++) {
            if (dis(t[i], t[j]) < d)
                d = dis(t[i], t[j]);
        }
    }
    return d;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> s[i].x >> s[i].y;
    sort(s + 1, s + 1 + n);
    cout << fixed << setprecision(4) << (cdq(1, n)) << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/nublity/p/11621595.html