平面最近点对:HDU1007:Quoit Design

题目描述戳这里
题解:
这题是平面最近点对的裸题。
感觉平面最近点对还是比较玄妙的。
这个算法用到的是分治的思想,先分为左右两边 ,然后合并其。
那么就具体来讲讲吧。
首先我们先按照x坐标来排序n个点。
然后就是求解过程,根据我前面说的,对于一段区间[L…R],我们求出它的中点mid,然后分治[l…mid],[mid+1…R]。
我们假设d=两段中较小的最短长度。
那么我们当前还要考虑合并的情况,也就是左边取一个点,右边取一个点的最短长度,我们要用它来修正d。
那么有一种比较暴力的方法,直接暴力枚举两边的元素,这样做的复杂度甚至比 O(n2) O ( n 2 ) 还要大。
但是我们可以在这种暴力的方法上进行一些优化。
我们可以考虑一下,那些点可能能够修正d,肯定至少要是x坐标距离中点mid的x坐标的距离 <d < d <script type="math/tex" id="MathJax-Element-421"> 我们可以从L~R扫一遍,找出这些点。
但是这样的总点数还是很多,如果有一大堆点都在mid附近的话复杂度还是会爆炸。
既然x坐标我们已经考虑了,我们干脆也限制一下y坐标。
我们将找出的这些点按y坐标排序,然后枚举每一个点i,用j向后推,如果j的y坐标-i的y坐标>0就可以break。
那么其实可以证明,这样的j最多只会有不超过8个,所以复杂度比较科学。
总复杂度:分制log,排序log,总共 O(nlog2(n)) O ( n ∗ l o g 2 ( n ) )
当然也可优化为 O(nlog(n)) O ( n ∗ l o g ( n ) ) ,这里就不讲了。

代码如下:

#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=100005;
const double inf=1e9;
int T,n,b[maxn];
struct dyt{
    double x,y;
}a[maxn];
double cmp(dyt a,dyt b) {return a.x<b.x;}
double cmp1(int x,int y){return a[x].y<a[y].y;}
double getdist(int i,int j){
    return sqrt(1.0*(a[i].x-a[j].x)*(a[i].x-a[j].x)+1.0*(a[i].y-a[j].y)*(a[i].y-a[j].y));
}
int abs_(int x){if (x<0) return -x; return x;}
double find(int l,int r) {
    if (l>=r) return inf;
    if (l+1==r) return getdist(l,r);
    int mid=(l+r)>>1;
    double d=min(find(l,mid),find(mid+1,r));
    int m=0;
    for (int i=l;i<=r;i++)
    if (abs_(a[i].x-a[mid].x)<=d) b[++m]=i;
    sort(b+1,b+1+m,cmp1);
    for (int i=1;i<=m;i++)
    for (int j=i+1;a[b[j]].y-a[b[i]].y<d&&j<=m;j++)
    d=min(d,getdist(b[i],b[j]));
    return d;
}
int main(){
    while (~scanf("%d",&n)) {
        if (n==0) break;
        for (int i=1;i<=n;i++) {
            scanf("%lf %lf",&a[i].x,&a[i].y);
        }
        sort(a+1,a+1+n,cmp);
        printf("%.2lf\n",find(1,n)/2.0);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值