[题解] [洛谷P7883] 平面最近点对(加强版)
[洛谷P1429] 平面最近点对(加强版)
题目描述#
给定平面上的
输入格式#
第一行:
接下来
输出格式#
仅一行,一个实数,表示最短距离,精确到小数点后4位。
题解#
如果暴力枚举,则复杂度为
考虑分治,将点按照横坐标排序编号后二分区间求解。边界条件是两个编号相同的点或者编号相邻的点,都可以方便的得到它们的距离。问题的关键是合并两个区间时如何计算跨区间的点之间的距离。所谓跨区间,实际上是分布在分割线两侧的点,即
考虑优化。优化的核心是减少枚举次数,即根据一定条件过滤不必要的枚举。因此我们加入枚举条件:假设两个区间内部的最优解是
如此便可解决此题~
题外话#
因为觉得调用sqrt会变慢,我一开始在分治的递归里只算了模没算距离,结果一直两个点TLE,调了半天发现把sqrt放到算模数的那里就行了,可能是double的大数运算太慢了吧... ?
AC代码#
#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;
}
分类:
ICPC日常练习
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)