hdu 1007(计算几何)

题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1007

题意:在平面上给你很多点,任意两点之间的最短距离。

分析:

一眼看到这个题想到暴力,二重循环,然后一看数据范围果断放弃,然后在网上查了一下就有一个方法可以在nlog(n)的方法求出,分治的思想,我现在听过分治就只在分治排序的那里听过。这个算法的原理是我们先对点进行按x大小进行排序,然后找出x的中位数(mid)在中位数的两边大概会有n/2个点,这个最近的点的距离(两个点)只会在mid左边,或者在mid的右边,最麻烦的可能是一个点在mid的左边另一个在mid的右边。这个算法的难点也在此,mid左边会得到一个最小值 ans1,右边最小值ans2,ans=min(ans1,ans2),如果在mid的两边的点会产生最小距离,则可能产生这些点x是会有一个范围的,mid左右两边扩展ans,得到如下图(别人的 嘿嘿)

然后在通过一个证明,证明太麻烦跳过了,可以得到要满足mid左边的一个和mid右边得一个点构成得距离小于ans,则一个左边的点最多对应右边6个点(可能说的不清楚,但是要说清楚很麻烦,很烦)要想彻底搞懂这个题可以去看看别人得博客 我很菜。

代码:模板吧

#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;

struct node {
    double x;
    double y;
}p[100050];
int a[100050];
bool cmpx(node qq,node ww)
{
    return qq.x<ww.x; //小到大
}
bool cmpy(int qq,int ww)
{
    return p[qq].y<p[ww].y; //小到大
}
double dis(node qq,node zz)
{
    return sqrt(((qq.x-zz.x)*(qq.x-zz.x))+((qq.y-zz.y)*(qq.y-zz.y)));
}

double find1(int l,int r)
{
    if(l+1==r) return dis(p[l],p[r]);
    if(l+2==r) return min(min(dis(p[l],p[l+1]),dis(p[l+1],p[r])),dis(p[l],p[r]));
    int mid=(l+r)/2;
    double ans;
    ans=min(find1(l,mid),find1(mid+1,r));
    int cnt=0;
    for (int i=l;i<=r;i++)
        if(p[i].x>=p[mid].x-ans&&p[i].x<=p[mid].x+ans)
            a[cnt++]=i;
    sort(a,a+cnt,cmpy);
    for (int i=0;i<cnt;i++)
    {
        for (int j=i+1;j<cnt&&j<i+7;j++)
        {
            ans=min(ans,dis(p[a[i]],p[a[j]]));
        }
    }
    return ans;
}
int main ()
{
    int n;
    while (scanf ("%d",&n)&&n)
    {
    for (int i=0;i<n;i++)
        scanf ("%lf %lf",&p[i].x,&p[i].y);
    sort(p,p+n,cmpx);
    //for (int i=0;i<n;i++)
      //  printf ("%lf %lf\n",p[i].x,p[i].y);
    printf ("%.2lf\n",find1(0,n-1)/2.0);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值