计算几何入门2——平面最近点对

一维

略。

二维

思想:

分治,排序

分治递归时,每次递归需要创造三个点集辅助比较,左右点集以及两者之间形成点对的点的点集

将n个点以横纵坐标为关键字进行排序,选取中间一点为分界点,将n个点分为两个点集;此时递归下去求出两点集各自的最近点对距离h1和h2;此时根据递归已求出h1和h2,选取其中最小的值作为h值,因为除了两点集内部的最小点集求出以外,还有两点集之间的点对距离未作比较;此时选取横坐标与参照点横坐标距离小于h的分别来自于左点集和右点集的点作为可能构成答案的点,将这些点单独放入一个点集;将得到的点集按照点的纵坐标进行排序并依次遍历该点集,对于每个点遍历纵坐标小于它但距离不超过h的点求出点对距离并更新答案,最终答案要么是h要么是更新后的答案。

时间复杂度:分治需要进行log2(n)次,每次分治通过巧妙借助归并排序已知可达到O(n)的复杂度,总复杂度为O(nlogn)

代码实现:
 
#include<bits/stdc++.h>
#include<algorithm>
#define ll long long
#define maxn 20000
#define INF 0x3f3f3f3f
using namespace std;
int n;
struct Point{
    double x;
    double y;
}pt[maxn],tmpt[maxn];
int cmp(Point a,Point b){
    return (a.x<b.x||(a.x==b.x&&a.y<b.y));
}
int cmpy(Point a,Point b)
{
    return (a.y<b.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));
}
double closest_pair(int l,int r)
{
    if(l==r)
    return INF;
    if(l+1==r)
    return dist(pt[l],pt[r]);
    int mid=(r+l)/2;
    double d1 = closest_pair(l, mid);
    double d2 = closest_pair(mid + 1, r);
    double d = min(d1, d2);
    int cnt=0;
    for(int i=l;i<=r;i++)
        if(fabs(pt[i].x-pt[mid].x)<d)
            tmpt[cnt++]=pt[i];
    sort(tmpt,tmpt+cnt,cmpy);//创建临时数组
    for(int i=0;i<cnt;i++)
        for(int j=i-1;j>=0&&(tmpt[i].y-tmpt[j].y)<d;j--)
        d=min(d,dist(tmpt[i],tmpt[j]));
    return d;
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    scanf("%lf%lf",&pt[i].x,&pt[i].y);
    sort(pt,pt+n,cmp);
    double ans=closest_pair(0,n-1);
    ans*=ans;
    printf("%.0f",ans);
    system("pause");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值