hdu 1007 Quoit Design

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

题目大意:最近点对。

题目分析:(1)假设有n(n≥3)个点,按x排序,编号为1~n。平均分成两部分,左边为1~m,最小距离为d1;右边为m+1~n,最小距离为d2。
(2)如果最小点对完全存在于左半部分或右半部分,则d=min(d1,d2);如果横跨两半部分,则继续讨论(3)。
(3)易知,符合要求的点到分界线m的距离≤d,我们将此范围内的点保存起来,并按y排序。
(4)思考一下问题:在一个长为2*d,宽为d的矩形区域内,存在x个点,它们两两之间的最小距离不大于d,求x的最大值。

(5)若i点和j点的y坐标之差大于当前最小值,则不再继续比较。由于这样的点最多6个,复杂度为O(1)。整个算法复杂度为O(nlogn),非常快!


代码参考:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 1e5 + 9;

struct Point//储存坐标
{
    double x, y;
}p[N], ans[N];

double dis(Point a, Point b)//计算两点之间的距离
{
    double x = a.x - b.x, y = a.y - b.y;
    return sqrt(x * x + y * y);
}

bool cmpx(Point a, Point b)//按x轴排序
{
    return a.x < b.x;
}

bool cmpy(Point a, Point b)//按y轴排序
{
    return a.y < b.y;
}

double cloest(int L, int R)
{
    if(L + 1 == R) return dis(p[L], p[R]);//如果只有两个点直接求其距离
    if(L + 2 == R) {//如果有3个点,求其两两之间的距离,取最小值
        double d1 = dis(p[L], p[L + 1]);
        double d2 = dis(p[L], p[R]);
        double d3 = dis(p[L + 1], p[R]);
        return min(d1, min(d2, d3));
    }
    int mid = (L + R) >> 1;//m为左右两半部分的分界线
    double rmin = min(cloest(L, mid), cloest(mid + 1, R));//递归求出两半部分的最小距离
    int cnt = 0;//记录符合要求的点的个数
    for(int i = L; i <= R; ++ i) {//搜索整个当前区间
        if(fabs(p[i].x - p[mid].x) <= rmin) {
            ans[cnt ++] = p[i];//把符合要求的点保存在ans数组里
        }
    }
    sort(ans, ans + cnt, cmpy);//按y轴排序
    for(int i = 0; i < cnt; ++ i) {//遍历所有符合要求的点
        for(int j = i + 1; j < cnt; ++ j) {
            if(ans[j].y - ans[i].y >= rmin) break;//若y轴之差大于当前的最小值,停止比较
            rmin = min(rmin, dis(ans[i], ans[j]));//更新最小值
        }
    }
    return rmin;
}

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);//按x轴排序
        printf("%.2lf\n", cloest(0, n - 1) / 2);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值