[题解] [洛谷P7883] 平面最近点对(加强版)

wxy3265·2024-04-12 20:35·104 次阅读

[题解] [洛谷P7883] 平面最近点对(加强版)

[洛谷P1429] 平面最近点对(加强版)

题目描述#

给定平面上的 n 个点,求其中距离最小的两个点之间的距离。

输入格式#

第一行: n ,保证 2n200000

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

输出格式#

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

题解#

如果暴力枚举,则复杂度为 O(n2),显然无法通过此题。

考虑分治,将点按照横坐标排序编号后二分区间求解。边界条件是两个编号相同的点或者编号相邻的点,都可以方便的得到它们的距离。问题的关键是合并两个区间时如何计算跨区间的点之间的距离。所谓跨区间,实际上是分布在分割线两侧的点,即 xi<xmid 的点和 xi>xmid 的点。两两枚举的时间复杂度显然是不行的。

考虑优化。优化的核心是减少枚举次数,即根据一定条件过滤不必要的枚举。因此我们加入枚举条件:假设两个区间内部的最优解是 d 只枚举距离分割线小于 d 的部分即可。但这样的时间复杂度依然不够优,因此需要考虑进一步优化。再加入枚举条件: 只计算纵坐标相差小于 d 的点。可以通过将符合条件的点按照纵坐标排序实现。

如此便可解决此题~

题外话#

因为觉得调用sqrt会变慢,我一开始在分治的递归里只算了模没算距离,结果一直两个点TLE,调了半天发现把sqrt放到算模数的那里就行了,可能是double的大数运算太慢了吧... ?

AC代码#

Copy
#include <algorithm> #include <iostream> #include <iomanip> #include <stack> #include <cmath> #define int long long using namespace std; const int MAXN = 2e5 + 3; int n; class Point { public: double x, y; } p[MAXN]; inline double getDis(Point a, Point b) { return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); } bool cmpX(Point a, Point b) {return a.x < b.x;} bool cmpY(Point a, Point b) {return a.y > b.y;} Point tmp[MAXN]; double solve(int l, int r) { if (r - l == 1) return getDis(p[l], p[r]); int mid = (l + r) >> 1; double ans = min(solve(l, mid), solve(mid, r)); double midx = p[mid].x; int cnt = 0; for (int i = l; i <= r; i++) { if (abs(p[i].x - midx) <= ans) { tmp[++cnt] = p[i]; } } sort(tmp + 1, tmp + 1 + cnt, cmpY); for (int i = 1; i < cnt; i++) { for (int j = i + 1; j <= cnt && tmp[i].y - tmp[j].y < ans; j++) { ans = min(ans, getDis(tmp[i], tmp[j])); } } return ans; } signed main() { cin >> n; for (int i = 1; i <= n; i++) { cin >> p[i].x >> p[i].y; } sort(p + 1, p + 1 + n, cmpX); cout << fixed << setprecision(4) << solve(1, n); return 0; }
posted @   wxy3265  阅读(104)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示
目录