最近点对

最近点对

pi=(xi,yi),表示平面上的一个点。
对于给定的点集S,求最近点对。

很容易想到O(n2)的算法。
计算每一对点的距离,然后取最小值。
但今天看分治的时候看到一种O(nlogn)的算法。

我们将点集合S按照x为第一关键字,y为第二关键字的大小升序排列,然后在拆分成集合大小相同的S1S2
根据分治的想法,最近点对只会有三种情况:

  • 两个点都在S1集合中
  • 两个点都在S2集合中
  • 一个在S1一个在S2

前面两种可以递归的寻找,所以问题在于处理第三种情况。
假设情况1的最近点对距离为h1,情况2的最近点对距离为h2h=min(h1,h2)
OIwiki上的这张图来观察一下:
nearest-points1
对于情况3的情况,所选的点对最好是位于中间中间轴左右h的区域内比较好,这个区域就是上图的B

上图是在x方向考虑,现在考虑y方向。
对于每一个在B中的pi,只需要找到另外一个点pj,且纵坐标绝对值之差小于h,考虑到重复的问题,我们让pj的纵坐标大于pi的纵坐标。有一个神奇的证明表示pj的个数最大为7。

于是对于情况3我们有了一个算法:

  1. 构建B
  2. B按照纵坐标排序
  3. 对于每一个pi,找到最近距离更新答案

接下来就是使用分治法解决问题了,时间复杂度为O(nlogn)【虽然不太会证明这个问题】

#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
#include <queue>
#include <cmath>
using namespace std;
#define ll long long
#define pii pair<ll,ll>
const ll N = 1e6+50;
const ll inf = 0x3f3f3f3f;
struct Pt{
    double x,y;
}pt[N];
ll n,f[N];
bool cmpxy(const Pt&a,const Pt& b){
    return a.x == b.x?a.y<b.y:a.x<b.x;
}
bool cmpy(const ll& a,const ll& b){
    return pt[a].y < pt[b].y;
}
double dis(ll i,ll j){
    ll dx = pt[i].x-pt[j].x,dy = pt[i].y-pt[j].y;
    return sqrt(dx*dx+dy*dy);
}
double close_pair(ll l,ll r){
    double h = 1e9+50;
    if(l == r) return h;
    if(l+1 == r) return dis(l,r);
    ll mid = l+r>>1;
    double h1 = close_pair(l,mid);
    double h2 = close_pair(mid+1,r);
    //cout<<h1<<' '<<h2<<endl;
    h = min(h1,h2);
    ll k = 0;
    for(ll i = l;i <= r;i++){
        if(fabs(pt[mid].x-pt[i].x) <= h)f[++k] = i;
    }
    sort(f+1,f+k+1,cmpy);
    for(ll i = 1;i <= k;i++){
        for(ll j = i+1;j <= k;j++){
            if(pt[f[j]].y-pt[f[i]].y >= h) break;
            //printf("%lld %lld %.4lf\n",f[i],f[j],dis(f[i],f[j]));
            h = min(h,dis(f[i],f[j]));
        }
    }
    //printf("%lld %lld %.4lf\n",l,r,h);
    return h;
}
int main() {
    //ios::sync_with_stdio(false);
    scanf("%lld",&n);
    for(ll i = 1;i <= n;i++) scanf("%lf%lf",&pt[i].x,&pt[i].y);
    sort(pt+1,pt+n+1,cmpxy);
//    for(ll i = 1;i <= n;i++){
//        printf("%lf %lf\n",pt[i].x,pt[i].y);
//    }
    printf("%.4lf\n",close_pair(1,n));
    return 0;
}
posted @   Paranoid5  阅读(448)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示