P1429 平面最近点对(加强版)【芙芙】

平面最近点对(加强版)

题目背景

P7883 平面最近点对(加强加强版)

题目描述

给定平面上 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

人类智慧高光时刻

P1429 平面最近点对(加强版)里最高赞题解写道:

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

AC CODE

#include<bits/stdc++.h>
#define pie acos(-1.0)
#define int long long int
using namespace std;
const int N=4e5+124;
int n;
int ans=1e16;
struct node{
	int x,y;	
}a[N];
bool cmp(node x,node y){
	return x.x<y.x;
}
int dist(int aa,int bb,int ac,int bc){
	return (aa-ac)*(aa-ac)+(bb-bc)*(bb-bc);
}
void work(double ang){
	ang=ang/180.0*pie;
	for(int i=1;i<=n;i++){
		int ax=a[i].x,ay=a[i].y;
		int ex,ey;
//		ex=ax*cos(ang)-ay*sin(ang);
//		ey=ax*sin(ang)-ay*cos(ang);
		ex=(ax-0.0)*cos(ang)-(ay-0.0)*sin(ang)+0.0;
		ey=(ax-0.0)*sin(ang)+(ay-0.0)*cos(ang)+0.0;
		a[i].x=ex,a[i].y=ey;
	}
	sort(a+1,a+1+n,cmp);
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=i+100&&j<=n;j++){
			if(i==j)continue;
//			ans=min(ans,dist(a[i].x,a[i].y,a[j].x,a[j].y));
			if(ans>dist(a[i].x,a[i].y,a[j].x,a[j].y)){
				ans=dist(a[i].x,a[i].y,a[j].x,a[j].y);
			}
		}
	}
}
signed main(){
	cin>>n;
	srand(time(NULL));
	for(int i=1;i<=n;i++){
		cin>>a[i].x>>a[i].y;
	}
	work(0);
	work(rand()%360);
	work(rand()%360);
	printf("%d\n",ans);
	return 0;
}

封面

请添加图片描述

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值