Quoit Design

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 58566    Accepted Submission(s): 15511

Problem 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
 
Author
CHEN, Yue
 
Source
【分析】:
 

平面最近点对,即平面中距离最近的两点

分治算法:

int SOLVE(int left,int right)//求解点集中区间[left,right]中的最近点对

{

double ans; //answer

0)    调用前的预处理:对所有点排序,以x为第一关键词y为第二关键字 , 从小到大;

1)    将所有点按x坐标分成左右两部分;

/*      分析当前集合[left,right]中的最近点对,有两种可能:

1. 当前集合中的最近点对,点对的两点同属于集合[left,mid]同属于集合[mid,right]

则ans = min(集合1中所有点的最近距离, 集合2中所有点的最近距离)

2. 当前集合最近点对中的两点分属于不同集合:[left,mid][mid,right]

则需要对两个集合进行合并,找出是否存在p∈[left,mid],q∈[mid,right],使得distance(p,q)小于当前ans(即步骤1中求得的ans);

*/

2)    Mid = (left+right)/2;

ans = min( SOLVE(left,mid), SOLVE(mid,right) );

即:递归求解左右两部分中的最近距离,并取最小值;

//此步骤实现上文分析中的第一种情况

/*

再次进行分析

我们将集合[left,right]用x = mid这条直线分割成两部分

则如果画出直线l1:x=mid-ans 和 l2:x=mid+ans,显然如果有p∈[left,mid], q∈[mid,right]且distance(p,q) < ans则p,q一定在直线l1和直线l2之间,否则distance(p,q)必定大于ans。

于是扫描出在l1和l2之间的点

*/

3)    建立缓存数组temp[];

for i = left TO right

{

如果 abs(Point[i].x - Point[mid].x) <= ans

则向temp中加入点Point[i];

}

/*

对于temp中的点,枚举求所有点中距离最近两点的距离,然后与ans比较即可。

枚举的时候不必两两枚举。观察下图中的点p

 
         不难发现,若有q∈[mid,mid+ans]使得distance(p,q) <
ans,则q点的位置一定在图中画出的一个2ans×ansd的矩形中。可以证明点集[mid,mid+ans]中的、矩形外的点与p点的距离一定大于ans。
           于是我们可以对temp以y为唯一关键字从小到大排序,进行枚举, 更新ans,然后在枚举时判断:一旦枚举到的点与p点y值之差大于ans,停止枚举。最后就能得到该区间的最近点对。

*/

4)    sort(temp);

for i = 0 TO k-1

{

for j = i+1 TO k-1

如果 temp[j].y - temp[i].y >= ans  break;

ans = min( ans, distance(temp[i], temp[j]) );

}

5)    return ans;

}

算法的时间复杂度

        由鸽巢原理,代码中第四步的枚举实际上最多只会枚举6个点,效率极高(一种蒟蒻的证明请看下方的评论)

本算法时间复杂度为O(n log n)

 
【代码】:

#include <bits/stdc++.h>
using namespace std; typedef long long LL;
const int N = +;
const int mod = ;
const double eps=1e-;
const int INF=0x7fffffff; int n; struct point{
double x,y;
point(double x=,double y=):x(x),y(y) {}
bool operator < (const point& p) const {
if(x!=p.x) return x<p.x;
else return y<p.y;
}
}p[N],tmp[N]; bool cmpy(point a,point b){
return a.y<b.y;
} double dis(point a,point b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
} double closest_pair(int left,int right){
double d=INF;
if(left==right)//如果此时区间查到了单点,直接返回最大值
return d;
if(left+==right) //如果左区间与右区间只差一,就直接返回他们的距离
return dis(p[left],p[right]);
int mid=(left+right)>>; //计算中点,位运算加速
double d1=closest_pair(left,mid); //分别计算出两个区间的值
double d2=closest_pair(mid,right);
d=min(d1,d2); //取两个区间中的最小值
int k=; //计算数量
for(int i=left;i<=right;i++){
if(fabs(p[mid].x-p[i].x)<=d){ //如果x轴的坐标相减满足<=d载入数组
tmp[k++]=p[i];
}
}
//按照y轴的值排序,默认按照升序
sort(tmp,tmp+k,cmpy); for(int i=;i<k;i++)
for(int j=i+;j<k&&tmp[j].y-tmp[i].y<d;j++){ //在已经筛出的数中计算最小值
double d3=dis(tmp[i],tmp[j]);
d=min(d,d3); //如果有最小值更新
}
return d; //直接返回最小值
} int main()
{
while(scanf("%d",&n),n){
for(int i=;i<n;i++){
double a,b;
scanf("%lf%lf",&a,&b);
p[i]=point(a,b);
}
sort(p,p+n); //化成有序数列
printf("%.2lf\n",closest_pair(,n-)/); //求的是半径,若求直径不必/2
}
return ;
}

平面点对

 

HDU 1007 Quoit Design【计算几何/分治/最近点对】的更多相关文章

  1. HDU 1007 Quoit Design(经典最近点对问题)

    传送门: http://acm.hdu.edu.cn/showproblem.php?pid=1007 Quoit Design Time Limit: 10000/5000 MS (Java/Oth ...

  2. hdu 1007 Quoit Design (经典分治 求最近点对)

    Problem Description Have you ever played quoit in a playground? Quoit is a game in which flat rings ...

  3. HDU 1007 Quoit Design 平面内最近点对

    http://acm.hdu.edu.cn/showproblem.php?pid=1007 上半年在人人上看到过这个题,当时就知道用分治但是没有仔细想... 今年多校又出了这个...于是学习了一下平 ...

  4. hdu 1007 Quoit Design(分治)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1007 题意:给出n个点求最短的两点间距离除以2. 题解:简单的分治. 其实分治就和二分很像二分的写df ...

  5. hdu 1007 Quoit Design(平面最近点对)

    题意:求平面最近点对之间的距离 解:首先可以想到枚举的方法,枚举i,枚举j算点i和点j之间的距离,时间复杂度O(n2). 如果采用分治的思想,如果我们知道左半边点对答案d1,和右半边点的答案d2,如何 ...

  6. HDU 1007 Quoit Design | 平面分治

    暂鸽 #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #d ...

  7. hdu 1007 Quoit Design 分治求最近点对

    Quoit Design Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tot ...

  8. hdu 1007 Quoit Design (最近点对问题)

    Quoit Design Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tot ...

  9. HDU 1007 Quoit Design(二分+浮点数精度控制)

    Quoit Design Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) To ...

随机推荐

  1. C++从键盘读入数组并存储

    C++从键盘读取任意长度的数组,现总结如下: //读取指定长度的数组 int main() { int n = 0; cin >> n; vector<int> p(n); f ...

  2. Codeforces:68A-Irrational problem(暴力大法好)

    A- Irrational problem p Time Limit: 2000MS Memory Limit: 262144K 64bit IO Format: %I64d& %I64 De ...

  3. PHP的抽象类、接口的区别和选择

    1.对接口的使用是通过关键字implements.对抽象类的使用是通过关键字extends.当然接口也可以通过关键字extends继承. 2.接口中不可以声明成员变量(包括类静态变量),但是可以声明类 ...

  4. iOS下单例模式实现(二)利用宏定义快速实现

    在上一节里提到了用利用gcd快速实现单例模式. 一个项目里面可能有好几个类都需要实现单例模式.为了更高效的编码,可以利用c语言中宏定义来实现. 新建一个Singleton.h的头文件. // @int ...

  5. 53、listview、expandableListview如何选中时保持高亮?

    一.listView被选中后保持高亮 70down voteaccepted To hold the color of listview item when you press it, include ...

  6. php伪随机数漏洞 以及脚本php_mt_seed的使用教程

    前几天在群里看到了一个题目,发现自己没有接触过这个伪随机数这个漏洞,在此记录下. 搜索这两个函数 mt_scrand() mt_rand() mt_scrand(seed)这个函数的意思,是通过分发s ...

  7. Android ListView用法

    写了一个简单的示例来说明ListView的用法:给定一个单词,下面有四个含义,找出正确的一个,无论是否成功,则会跳转到下一个单词:主要用到的知识有: findViewById().  ListView ...

  8. Python 拓展之详解深拷贝和浅拷贝

    正式开始 首先我在这介绍两个新的小知识,要在下面用到.一个是函数 id() ,另一个是运算符 is.id() 函数就是返回对象的内存地址:is 是比较两个变量的对象引用是否指向同一个对象,在这里请不要 ...

  9. [oldboy-django][6其他]备份数据库和导入数据库

    # 备份数据库 - 简单备份 mysqldump -uroot -pec494904 ecmangent-mobile > /tmp/backfile.sql 表结构+数据 - --opt my ...

  10. [WC2013][luogu4074] 糖果公园 [树上带修改莫队]

    题面: 传送门 思路: 一道实现起来细节比较恶心的题目 但是其实就是一个裸的树上带修改莫队 好像树上莫队也出不了什么结合题目,不像序列莫队天天结合AC自动机.后缀数组...... 莫队学习请戳这里:莫 ...