平面最近点对题解
题意
给定平面上 \(n\) 个点,找出其中的一对点的距离,使得在这 \(n\) 个点的所有点对中,该距离为所有点对中最小的。
输入格式
第一行:\(n\) ,保证 \(2\le n\le 200000\) 。
接下来 \(n\) 行:每行两个整数:\(x\ y\) ,表示一个点的行坐标和列坐标,中间用一个空格隔开。
输出格式
仅一行,一个实数,表示最短距离,精确到小数点后面 \(4\) 位。
题解
- 使用CDQ分治找平面中最近的两点。
- 首先将所有的点按坐标\(x\)排序,将点集划分为两部分(以\(x\)处于中间的点为界),于是左右两个平面被划分为两个思想一致的子问题,递归求解得到左,右平面内的最小距离\(d_{min} = min(L_{min},R_{min})\),还需考虑跨左右平面的最短距离是否会更小,以中点为基准,若一个点到中点\(x,y\)方向上距离比最短距离\(d_{min}\)还长,就不可能对答案做出贡献,于是找出所有可能对答案有贡献的点,计算他们的两两之间的距离,与\(d_{min}\)比较维护\(d_{min}\)即可
伪代码

AC 代码
#include <bits/stdc++.h>
#define ll long long
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);
#define endl '\n'
const int inf = 0x3f3f3f3f;
const ll infll = 0x3f3f3f3f3f3f3f3f;
const double PI = acos(-1.0);
using namespace std;
//ifstream fin("input.txt");
//ofstream fout("output.txt");
//#define cin fin
//#define cout fout
const int N = 2e5+5;
int n;
struct point
{
int x,y;
};
double dist(point& a,point& b) {
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
bool cmp(point& a,point& b) {
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
bool cmpy(point&a ,point& b) {
return a.y<b.y;
}
point points[N];
double solve(int l,int r) {
if(l==r) return inf;
if(l+1==r) return dist(points[l],points[r]);
int mid = (l+r)>>1;
double d1 = solve(l,mid);
double d2 = solve(mid+1,r);
double mind = min(d1,d2);
vector<point> tmp;
for(int i=l;i<=r;i++) {
if(fabs(points[i].x-points[mid].x)<=mind) {
tmp.push_back(points[i]);
}
}
sort(tmp.begin(),tmp.end(),cmpy);
for(int i=0;i<tmp.size() ;i++) {
for(int j=i+1;j<tmp.size() && fabs(tmp[i].y-tmp[j].y)<=mind;j++) {
double d=dist(tmp[i],tmp[j]);
mind=min(mind,d);
}
}
return mind;
}
signed main()
{
IOS
cin>>n;
for(int i=1;i<=n;i++) cin>>points[i].x>>points[i].y;
sort(points+1,points+n+1,cmp);
cout<<fixed<<setprecision(4)<<solve(1,n);
//fin.close(),fout.close();
return 0;
}

浙公网安备 33010602011771号