【计算理论与算法分析设计】 4. 套圈 (HDU-1007)

套圈

Description

Have you ever played quoit in a playground? Quoit is a game in which flat rings are pitched at some toys, with all the toys encircled awarded. In the field of Cyberground, the position of each toy is fixed, and the ring is carefully designed so it can only encircle one toy at a time. On the other hand, to make the game look more attractive, the ring is designed to have the largest radius. Given a configuration of the field, you are supposed to find the radius of such a ring. Assume that all the toys are points on a plane. A point is encircled by the ring if the distance between the point and the center of the ring is strictly less than the radius of the ring. If two toys are placed at the same point, the radius of the ring is considered to be 0.

Input

The input consists of several test cases. For each case, the first line contains an integer N (2 <= N <= 100,000), the total number of toys in the field. Then N lines follow, each contains a pair of (x, y) which are the coordinates of a toy. The input is terminated by N = 0.

Output

For each test case, print in one line the radius of the ring required by the Cyberground manager, accurate up to 2 decimal places.

Sample Input

2
0 0
1 1
2
1 1
1 1
3
-1.5 0
0 0
0 1.5
0

Sample Output

0.71
0.00
0.75

题目描述

给定一些玩具的位置,求出距离最近的一对玩具之间的距离的一半(即最近点对问题)。需要注意的是,求出最近距离之后还要除以2,因为所要求的其实是套圈所使用的圈的半径。

问题分析

数据范围是2 <= N <= 100,000,所以如果枚举每两个玩具之间的距离,时间复杂度为O(n2),肯定是不可行的。我们可以采用分治法解决这一问题。课本《计算机算法设计与分析(第5版)》(王晓东)中给出了分治法计算最近点对问题的思路,大致如下:

  1. 设m为N个点的x坐标的中位数;
  2. 将所有点划分为两个集合:S1——x坐标小于等于m的点集;S2——x坐标大于m的点集;
  3. 递归地求解S1与S2中的最近点对距离,分别设为d1和d2;
  4. 设dm=min(d1,d2),设P1是S1中x坐标与m之差的绝对值小于dm的点集,P2是S2中x坐标与m之差的绝对值小于dm的点集;
  5. 将P1与P2中的点按照y坐标排序,设X和Y分别是排好序的点列;
  6. 对于X中的每一个点,检查Y中与其距离在dm之内的所有点(由鸽巢原理可以证明最多有6个点,详见课本),即Y中的扫描指针可以在宽度为2dm的一个区间内移动,求出最小距离为d1;
  7. 所有点的最近点对距离即为min(dm,d1)。

和上一篇博客一样,这里要吐槽一下课本。课本上的代码先是给出了两个点类(class),还有运算符重载,最后计算最近点对距离的函数有8个参数,还不告诉都是什么含义,代码中间的注释也极少,导致在学习时看那段代码就看了得有一两个小时才明白在干什么……并且,上述思路的第6步,看起来很合理,节约了时间,但实际上这不是一种计算思维的描述,实现起来也不好实现,并且我感觉课本上给出的代码,也与这个思路不太一样,也是把所有P1与P2中的点对都考察了一遍,感觉并不能减少for循环的执行次数……

下面的AC代码将上面思路的第4-7步修改如下,同样能够通过本题:

  1. 设dm=min(d1,d2),设P为S1和S2中x坐标与m之差的绝对值小于dm的点集;
  2. 将P中的点按照y坐标排序;
  3. 对于P中的任意两点,如果它们的y坐标之差小于dm,则计算它们之间的距离,如果小于dm,则更新dm;
  4. 最后dm的值即为最小距离。

AC代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
struct point
{
    double x,y;
}p[100005];
int q[100005];
bool cmpx(point p,point q) //x坐标排序比较函数
{
    return p.x<q.x;
}
bool cmpy(int p1,int q) //y坐标排序比较函数
{
    return p[p1].y<p[q].y;
}
double dist(point p,point q) //计算距离函数
{
    return sqrt((p.x-q.x)*(p.x-q.x)+(p.y-q.y)*(p.y-q.y));
}
double mindist(int l,int r) //计算最近点对距离函数
{
    if (r-l==1) return dist(p[l],p[r]); //两个点的情况,直接计算
    else if (r-l==2) //三个点的情况
    {
        double x=dist(p[l],p[l+1]),y=dist(p[l+1],p[r]),z=dist(p[l],p[r]);
        if (x<y) swap(x,y);
        if (y<z) swap(y,z);
        if (x<z) swap(x,z);
        return z;
    }
    else //四个及以上点的情况,分治
    {
        int mid=(l+r)/2; //中位数
        double minn=min(mindist(l,mid),mindist(mid+1,r)); //递归地求两部分的最近点对距离
        int k=0;
        for (int i=l;i<=r;i++) //找出与中位数x坐标之差绝对值在minn内的点
        {
            if (fabs(p[i].x-p[mid].x)<minn)
            {
                q[k]=i; //q存的是点的编号
                k++;
            }
        }
        sort(q,q+k,cmpy); //按y坐标排序
        for (int i=0;i<k;i++)
        {
            for (int j=i+1;j<k&&p[q[j]].y-p[q[i]].y<minn;j++) //如果两个点的y坐标之差小于minn,就考察它们之间的距离,如果距离小于minn就更新minn
            {
                double d=dist(p[q[i]],p[q[j]]);
                if (d<minn) minn=d;
            }
        }
        return minn;
    }
}
int main()
{
    int n;
    while (scanf ("%d",&n)!=EOF)
    {
        if (n==0) break;
        for (int i=0;i<n;i++)
        {
            scanf ("%lf%lf",&p[i].x,&p[i].y);
        }
        sort(p,p+n,cmpx);
        double ans=mindist(0,n-1);
        printf ("%.2lf\n",ans/2); //这里别忘了除以2
    }
    return 0;
}

当时写这个代码的时候,有一点疑问一直不知道是为什么,就是代码的第43行,我存的是点的编号。如果直接存y坐标的话,在杭电OJ和乐学上面提交都会TLE,但存点的编号,然后将按y坐标排序的比较函数那里再去寻找y坐标,第50行的for循环条件改成p[q[i]].y的形式去找y坐标,就不会超时。匪夷所思,最后也没想明白。

而且,我比较怀疑第50行加上p[q[j]].y-p[q[i]].y<minn这个条件之后,究竟能节省多少时间,因为这不能减少for循环的循环次数,节省的只是调用函数求距离的时间。

并且,突然发现了代码写得不太好的地方——我考察的是x坐标与中位数之差的绝对值小于minn的所有点对,其实有相当多一部分是不需要考察的——如果它们同出自点集S1,或同出自点集S2,则它们就不需要考察了。我们只需要考察出自不同点集的两点之间的距离。如果像我这么写的话,貌似按照y坐标排序这一步也可以省去。。。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
算法计算理论手册提出广泛的处理算法,数据结构和计算理论。 在这种学科的主科地区周围组织,这种资源在有关的科学和工程学科里服务于计算机科学家,工程师和其他专业人士。 书包含来自应用领域说明基本的概念和技术怎样一同来提供优雅的解决重要的实际的问题的方法的章。 提出反映出开业医生的需要的一个平衡的远景。 给算法和数据结构包括更多页比适合理论期的完全。 在它的理论的问题的讨论过程中强调实际的应用。 包含在字符串匹配,数据结构和有限的精密上的广泛的讨论。 提供彻底的B树的报告。 集中于实际的算法,即使他们不渐近最佳。 略述算法的技术具有关键的重要性的具体的申请 算法计算理论手册是一次也包括很多理论的问题的算法和数据结构的广泛的收集。 它提供反映出开业医生的需要的一个平衡的远景,在在理论的问题上的讨论内包括关于应用的重点。 章包括关于算法的技术特别重要的具体的算法的有限的精密问题和讨论的信息, 包括图画,机器人技术,形成VLSI 片,视力和图象处理,数据压缩和密码术。 书也提出在和平行/ 分布计算的组合优化的一些先进题目。组织技术的算法和数据特别重要的应用领域 图画 机器人算法 VLSI 布局 视力和图像处理算法 安排 电子现金 数据压缩 动态的图算法 在线算法 多维数据结构 密码术 在组合优化和平行/被分配的计算里的高级题目 算法计算理论手册的独特的新闻报导为研究人员和在这些应用领域的开业医生使它为必要的参考。 Algorithms and Theory of Computation Handbook presents a comprehensive treatment of algorithms, data structures, and theory of computation. Organized around the main subject areas of the discipline, this resource serves computer scientists, engineers, and other professionals in related scientific and engineering disciplines. The book contains chapters from application areas illustrating how fundamental concepts and techniques come together to provide elegant solutions to important practical problems. Presents a balanced perspective reflecting the needs of the practitioner. Includes more pages for algorithms and data structures than for purely theoretical issues. Emphasizes practical applications in its discussion of theoretical issues. Contains extensive discussions on string matching, data structures, and finite precision. Provides thorough reporting of B-trees. Focuses on practical algorithms even if they are not asymptotically optimal. Outlines specific applications where algorithmic techniques are of critical importance Algorithms and Theory of Computation Handbook is a comprehensive collection of algorithms and data structures that also covers many theoretical issues. It offers a balanced perspective that reflects the needs of practitioners, including emphasis on applications within discussions on theoretical issues. Chapters include information on finite precision issues as well as discussion of specific algorithms where algorithmic techniques are of special importance, including graph drawing, robotics, forming a VLSI chip, vision and image processing, data compression, and cryptography. The book also presents some advanced topics in combinatorial optimization and parallel/distributed computing. · applications areas where algorithms and data structuring techniques are of special importance · graph drawing · robot algorithms · VLSI layout · vision and image processing algorithms · scheduling · electronic cash · data compression · dynamic graph algorithms · on-line algorithms · multidimensional data structures · cryptography · advanced topics in combinatorial optimization and parallel/distributed computing Unique coverage of Algorithms and Theory of Computation Handbook makes it an essential reference for researchers and practitioners in these applications areas.

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值