算法分析与设计——最近点对问题

探讨通过分治策略解决最近点对问题,旨在设计一个圆环,使其最多套住一个平面上的小礼品点,重点在于计算点集的最近距离。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

算法分析与设计——最近点对问题

题目

这个题目目前对于大家会有点难度,有兴趣的同学可以研究一下,这种题目才是分治的精髓所在。

前段时间 partychen 到吴泾去买东西,发现在步行街有一个赌博游戏,一个商人在地面上摆放了很多的小礼品,然后准备了很多大小相同的圆环,玩家可以到商人处花 5 块钱买一个圆环。然后站在一根白线外使用圆环套住自己想要的礼品。圆环套住的东西就归玩家所有。我这里描述的不是很清楚,但是我相信大家肯定也知道这个是什么游戏了。

出于商人的本性,他现在想邀请计算机的你,帮助他设计一个圆环,使得这个圆环最多只能套住一个小礼品。

为了让问题简单化,我们假设每一个小礼品都是平面上的一个点。如果点在圆环上也算套住。当然如果两个礼品重叠放置的话 那么圆环的半径显然会是 0。

他只要你求出这个圆环的半径。

输入

输入数据有多组,每组测试数据第一行有一个正整数 N (2≤N≤100000), 表示平面上有多少个点。然后有 N 组实数对 (x,y) (−1000≤x,y≤1000) 表示点的坐标。如果 N=0 表示输出结束,并且不作处理。

输出

对于每组测试数据,输出圆环的半径,结果保留两位小数。每个输出占一行。

样例

在这里插入图片描述

问题分析

所求的圆环最小半径实际上是给定点集的最近距离的一半,因此只要遍历点集计算所有点对之间的距离,找到最小距离即可。假设有n个点,如果挨个计算所有点对之间的距离,则需要的时间为 Θ(n*(n-1)/2) 。如果采用分治策略,将点集分为左半部分 (l,mid) 和右半部分 (mid+1,r) ,分别计算出两部分的最近点对距离 minl 和 minr,再找到分别从左半部分和右半部分各取一个点组成的点对的最近距离min,最近点对距离就是这三个值中的最小值。这种情况下,T(n) = 2*T(n/2)+n^2/4 = … = 2n+1/2n^2。(欸欸欸?变多了?…先不管吧)

代码

double min_dist(int l, int r)
{
    if(l == r)
        return 8000001;//最远点对距离的平方为8000000
    if(l == r-1)
        return sqrt((points[l][0]-points[r][0])*(points[l][0]-points[r][0])+(points[l][1]-points[r][1])*(points[l][1]-points[r][1]));
    int mid = (l+r)/2;
    double minl = min_dist(l,mid);
    double minr = min_dist(mid+1,r);
    int i,j;
    double min = 8000001,tmp;
    for(i = l; i <= mid; i++)
    {
        for(j = mid+1; j <= r; j++)
        {
            tmp = (points[i][0]-points[j][0])*(points[i][0]-points[j][0])+(points[i][1]-points[j][1])*(points[i][1]-points[j][1]);
            if(tmp < min)
                min = tmp;
        }
    }
    min = sqrt(min);
    min = min>minl ? minl : min;
    min = min>minr ? minr : min;
    return min;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值