平面最近点对(加强版)

平面最近点对(加强版)

题目描述

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

输入格式

第一行: n n n ,保证 2 ≤ n ≤ 200000 2\le n\le 200000 2n200000

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

输出格式

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

样例 #1

样例输入 #1

3
1 1
1 2
2 2

样例输出 #1

1.0000

提示

数据保证 0 ≤ x , y ≤ 1 0 9 0\le x,y\le 10^9 0x,y109

思路

不同于 平面最近点对(加强加强版),之前使用了分治,过于繁琐,而对于这个题来说,可能有更加方便的做法

我们充分发扬人类智慧:
将所有点全部绕原点旋转同一个角度,然后按 x x x 坐标排序
根据数学直觉,在随机旋转后,答案中的两个点在数组中肯定不会离得太远
所以我们只取每个点向后的 5 5 5 个点来计算答案
这样速度快得飞起,在 n = 1000000 n=1000000 n=1000000 时都可以在 1 s 1 s 1s 内卡过

实现上述做法,需要点旋转公式:
x ′ = ( x − x 0 ) ∗ c o s ( θ ) + ( y − y 0 ) ∗ s i n ( θ ) + x 0 x'= (x - x_0)*cos(\theta) + (y - y_0)*sin(\theta) + x_0 x=(xx0)cos(θ)+(yy0)sin(θ)+x0

y ′ = − ( x − x 0 ) ∗ s i n ( θ ) + ( y − y 0 ) ∗ c o s ( θ ) + x 0 y'=-(x - x_0)*sin(\theta) + (y - y_0)*cos(\theta) + x_0 y=(xx0)sin(θ)+(yy0)cos(θ)+x0
若绕原点,则可以代入求解

代码

#include <bits/stdc++.h>
#define int double
#define hp(x,y,a,b) (x-a)*(x-a)+(y-b)*(y-b)
using namespace std;
const long M=1e7;
int a[M],b[M];
struct node{
	int x,y;long id;
}p[M];
void calc(int x,int y,int b,long i){
	int tx,ty;
	tx=x*cos(b)-y*sin(b);
	ty=x*sin(b)+y*cos(b);
	p[i]=(node){tx,ty,i};
}
int dist=1e19;
int read(){int x;cin>>x;return x;}
long n;
signed main(){
	cin>>n;
	for(long i=1;i<=n;i++)
		calc(a[i]=read(),b[i]=read(),56,i);
	
	sort(p+1,p+1+n,[](node x,node y){return x.x<y.x;});
	for(long i=1;i<=n;i++)
		for(long j=i+1;j<=min(n,i+2);j++)
			dist=min(hp(a[p[i].id],b[p[i].id],a[p[j].id],b[p[j].id]),dist);
	printf("%.4lf",sqrt(dist));
	return 0;
} 
  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值