算法实践5 最近点对

问题:

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

解析

考虑暴力的方法,需要判断所有点对的距离。当\(n\)较小时,比较容易求解。合并两个区间时,可以考虑两个区间的最小值,只有当两个区间的点对距离不超过这个最小值时才会有意义。我们分别考虑\(x\)轴方向和\(y\)轴方向,就能及时终止遍历,达到一个较优的时间复杂度。所以采用分治策略来解决。

设计

double gao(int l, int r) {
    处理区间点较少的情况
    double ans = min(gao(l, mid), gao(mid + 1, r));
    for (i = l -> r) 
        找出所有p[i].x - p[mid].x <= ans 的点,记总数为tot
    按y轴值进行排序
    for (i = 1 -> tot)
        for (j = i + 1 -> tot)
            if (两点y的距离大于ans) break;
    		更新ans
    return ans;
}

分析

因为对\(x\)\(y\)的大小做了限制,遍历的复杂度并不会太高,在快排存在时可近似看成常数,合并复杂度为\(O(nlogn)\),分治复杂度为\(O(logn)\),总复杂度为\(O(nlog^2n)\)

源码

https://github.com/Sstee1XD/Algorithm_homework/tree/main/实验5 最近点对

#include <bits/stdc++.h>

using namespace std;

#define endl "\n"

const int N = 2e5 + 7;

struct Point {
    double x, y;
    Point () {}
    Point(double x, double y) : x(x), y(y) {}
}p[N], tmp[N];

bool cmp1(Point a, Point b) {
    if (a.x == b.x) return a.y < b.y;
    return a.x < b.x;
}

bool cmp2(Point a, Point b) {
    if (a.y == b.y) return a.x < b.x;
    return a.y < b.y;
}

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

int n;

double gao(int l, int r) {
    int num = r - l + 1;
    if (num == 1) return 1e50;
    if (num == 2) return getDist(p[l], p[r]);
    int mid = l + r >> 1;
    double ans = min(gao(l, mid), gao(mid + 1, r));
    int tot = 0;
    for (int i = l; i <= r; ++i) {
        if (fabs(p[mid].x - p[i].x) <= ans) tmp[++tot] = p[i];
    }
    sort(tmp + 1, tmp + 1 + tot, cmp2);
    for (int i = 1; i <= tot; ++i) {
        for (int j = i + 1; j <= tot; ++j) {
            if (tmp[j].y - tmp[i].y > ans) break;
            ans = min(ans, getDist(tmp[i], tmp[j]));
        }
    }
    return ans;
}

void solve() {
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        double x, y;
        cin >> x >> y;
        p[i] = Point(x, y);
    }
    sort(p + 1, p + 1 + n, cmp1);
    cout << gao(1, n) << endl;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    cout << fixed << setprecision(4);
    int t = 1;
    while (t--) solve();
    return 0;
}
posted @ 2021-06-21 23:23  stff577  阅读(103)  评论(0)    收藏  举报