【SSL】1726&【洛谷】P1257&【洛谷】P1429平面最近对点

【SSL】1726&【洛谷】P1257&【洛谷】P1429平面最近对点

【SSL】1726

Time Limit:10000MS Memory Limit:65536K
Case Time Limit:1000MS

Description

在应用中,常用诸如点、圆等简单的几何对象代表现实世界中的实体。在涉及这些几何对象的问题中,常需要了解其邻域中其它几何对象的信息。例如,在空中交通控制问题中,若将飞机作为空间中移动的一个点来看待,则具有最大碰撞危险的2架飞机,就是这 个空间中最近的一对点。这类问题是计算几何中研究的基本问题之一。下面我们着重考虑平面上的最接近点对的问题。
最接近对点问题的提法是:给定平面上n个点,找出其中的一对点,使得在n个点的所有点对中,该点对的距离最小。严格地说,最接近点对可能多于一对。为了简单起见,这里只限于找其中的一对。

Input

平面中各点的坐标,以0 0结束。

Output

距离最近的两点坐标。

Sample Input

7 2
2 7
3 4
9 7
0 0

Sample Output

3.16

【洛谷】P1257

题目描述

给定平面上 n 个点,找出其中的一对点的距离,使得在这 n 个点的所有点对中,该距离为所有点对中最小的。

输入格式

第一行一个整数 n,表示点的个数。

接下来 n 行,每行两个实数x,y ,表示一个点的行坐标和列坐标。

输出格式

仅一行,一个实数,表示最短距离,四舍五入保留 44 位小数。

输入输出样例

输入

3
1 1
1 2
2 2

输出

1.0000

说明/提示

数据规模与约定
对于100% 的数据,保证 1 ≤ n ≤ 1 0 4 , 0 ≤ x , y ≤ 1 0 9 1 \leq n \leq 10^4 ,0 \leq x, y \leq 10^9 1n1040x,y109 ,小数点后的数字个数不超过 6。

【洛谷】P1429

题目描述

给定平面上n个点,找出其中的一对点的距离,使得在这n个点的所有点对中,该距离为所有点对中最小的

输入格式

第一行:n;2≤n≤200000

接下来n行:每行两个实数:x y,表示一个点的行坐标和列坐标,中间用一个空格隔开。

输出格式

仅一行,一个实数,表示最短距离,精确到小数点后面4位。

输入输出样例

输入

3
1 1
1 2
2 2

输出

1.0000

说明/提示

0<=x,y<=109

思路

考虑用分治
ans表示n个点的最近点对距离,先判重,如有点重合ans=0。
否则把n个点尽可能均分为左右两部分,ans的值只有以下3种情况:
①左边部分的最近点对距离d1
②右边部分的最近点对距离d2
③左半部分的点与右半部分点形成的最小距离d3
ans=min(min(d1,d2),d3)
左右两部分的最近点对问题是与原问题结构性质一样的子问题,可以递归求解出d1,d2
d3表示左半部分的点到右半部分点的最短距离,如果存在点对使得d3<d,则点对中的两个点必定都在距离直线L(分界线)d的单位之内。如图所示,它们必定处于以直线L为中心、宽度为2d的垂直带形的区域内。
在这里插入图片描述

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
struct jgt
{
	double x,y;
}a[200010],b[200010];
bool cmp(jgt t1,jgt t2)
{
	if(t1.x==t2.x)return t1.y<t2.y; 
	return t1.x<t2.x;
}
double dis(jgt t1,jgt t2)
{
	return sqrt((t1.x-t2.x)*(t1.x-t2.x)+(t1.y-t2.y)*(t1.y-t2.y));
}
double find(int l,int r)
{
	if (l==r)return 0x7f7f7f7f;
	if (l+1==r)return dis(a[l],a[r]);
	int tot=0,mid=(l+r)>>1,i,j;
	double d=min(find(l,mid),find(mid+1,r));
	for(i=l;i<=r;i++) 
		if(fabs(a[i].x-a[mid].x)<=d)b[tot++]=a[i];
	for(i=0;i<tot;i++)
		for(j=i+1;j<tot;j++)
			d=min(d,dis(b[i],b[j]));
	return d;
}
int main()
{
	int n,i;
	for(scanf("%d",&n),i=1;i<=n;i++)scanf("%lf%lf",&a[i].x,&a[i].y);
	sort(a+1,a+n+1,cmp);
	for(i=1;i<n;i++)
		if(a[i].x==a[i+1].x&&a[i].y==a[i+1].y){printf("0.0000");return 0;}
	printf("%.4f",find(1,n));
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值