平面最近点对 平方级算法 绝对值不等式

题目大意:给 n 个整点,求其最近点对距离。

算法思路:
第一步,将点 1 到点 n-1 按距离点 0 由近及远排序,重编号点 1 到点 n-1;
第二步,设当前最小距离 answer := Distance(Point_0, Point_1),从点 1 到点 n-2 依次进行以下操作;
第三步,对于点 i,从点 i+1 到点 n-1 依次查询与点 i 的距离,若更近则更新当前最小距离 answer;
第四步,对于点对 (Point_i, Point_j),若有
D i s t a n c e ( P o i n t 0 , P o i n t j ) − D i s t a n c e ( P o i n t 0 , P o i n t i ) > a n s w e r Distance(Point_0, Point_j) - Distance(Point_0, Point_i) > answer Distance(Point0,Pointj)Distance(Point0,Pointi)>answer
则对于点 k (j < k < n),有
D i s t a n c e ( P o i n t i , P o i n t k ) &gt; D i s t a n c e ( P o i n t 0 , P o i n t k ) − D i s t a n c e ( P o i n t 0 , P o i n t i ) &gt; D i s t a n c e ( P o i n t 0 , P o i n t j ) − D i s t a n c e ( P o i n t 0 , P o i n t i ) &gt; a n s w e r \begin{matrix} Distance(Point_i, Point_k) &amp;&gt; &amp;Distance(Point_0, Point_k) - Distance(Point_0, Point_i) \\ &amp;&gt; &amp;Distance(Point_0, Point_j) - Distance(Point_0, Point_i) \\ &amp;&gt; &amp;answer \end{matrix} Distance(Pointi,Pointk)>>>Distance(Point0,Pointk)Distance(Point0,Pointi)Distance(Point0,Pointj)Distance(Point0,Pointi)answer
距离必远于当前最小距离,跳过。

测试结果显示,对于随机稀疏数据,该算法表现与 O(nlogn) 级别算法相差不大;对于构造密集数据,该算法退化明显。

在算法初始时,可以随机调换点 0,以防止出现通过构造点 0 位置的数据使算法运行效率降低的情况。不过,既然点 0 位置是构造出的,那么其他点的位置很大可能是整齐有序的,在此情况下该算法运行效率不高,故该优化意义不大。

代码如下:

#include<algorithm>
#include<math.h>
#include<stdio.h>
#define MAX_N (100005)
#define Distance(x0,y0,x1,y1) (sqrt(((x1)-(x0))*((x1)-(x0))+((y1)-(y0))*((y1)-(y0))))
struct POINT
{
	int x,y;
	double d0;
}xy[MAX_N];
bool cmp(POINT p,POINT q)
{
	return p.d0<q.d0;
}
int main()
{
	int n;
	double ans;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
		scanf("%d %d",&xy[i].x,&xy[i].y);
	for(int i=1;i<n;i++)
		xy[i].d0=Distance((double)xy[0].x,(double)xy[0].y,(double)xy[i].x,(double)xy[i].y);
	std::sort(xy+1,xy+n,cmp);
	ans=xy[1].d0;
	for(int i=1;i<n;i++)
		for(int j=i+1;j<n&&xy[j].d0-xy[i].d0<ans;j++)
			if(Distance((double)xy[i].x,(double)xy[i].y,(double)xy[j].x,(double)xy[j].y)<ans)
				ans=Distance((double)xy[i].x,(double)xy[i].y,(double)xy[j].x,(double)xy[j].y);
	printf("%.2lf",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值