poj 3714 Raid(平面最近点对)

本文介绍了一种计算两个点集间最近距离的有效算法。通过将点集标记并使用平面最近点对的方法,避免了旋转卡壳的问题。文章提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给出两个点集,然后求两个点集之间的最近距离。

思路:开始用的旋转卡壳,两个点集先求凸包,这样就变成了两个凸包间最近距离,但是死活TLE,然后就换了平面最近点对来做,把两个点集标记一下,判断下是不是在同一个点集里就行了

#include <algorithm> 
#include <iostream> 
#include <cmath> 
using namespace std; 

const int N=200002; 
const double EPS=1e-10; 
const double INF=1e20; 

struct Point
{ 
	double x,y; 
	bool flag;
} p[N]; 
int n,o[N],on; 

inline double dis(const Point & a,const Point & b)
{ 
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
} 
inline int dcmp(double a,double b)
{ 
	if(a-b<EPS && b-a<EPS) return 0; 
	if(a>b) 
		return 1; 
	return -1; 
} 
inline bool cmp_x(const Point & a,const Point & b)
{ 
	return dcmp(a.x,b.x)<0; 
} 
inline bool cmp_y(const int & a,const int & b)
{ 
	return dcmp(p[a].y,p[b].y)<0; 
} 
inline double min(double a,double b)
{ 
	return a<b ? a : b; 
} 
double search(int s,int t,Point& x,Point& y)
{ 
	int mid=(s+t)>>1,i,j; 
	double getRet,getDis,ret=INF; 
	Point getx,gety; 
	if(s>=t) return ret; 
	for(i=mid;i>=s && ! dcmp(p[i].x,p[mid].x);--i); 
	ret=search(s,i,x,y); 
	for(i=mid;i<=t && ! dcmp(p[i].x,p[mid].x);++i); 
	getRet=search(i,t,getx,gety); 
	if(getRet<ret)
	{ 
		ret=getRet; 
		x=getx; 
		y=gety; 
	} 
	on=0; 
	for(i=mid;i>=s && dcmp(p[mid].x-p[i].x,ret)<=0;--i) 
		o[++on]=i; 
	for(i=mid+1;i<=t && dcmp(p[i].x-p[mid].x,ret)<=0;++i) 
		o[++on]=i; 
	sort(o+1,o+on+1,cmp_y); 
	for(i=1;i<=on;++i)
	{ 
		for(j=1;j<=10;++j)
		{ 
			if(p[o[i]].flag==p[o[i+j]].flag)
				continue;
			getDis=dis(p[o[i]],p[o[i+j]]); 
			if(i+j<=on&&getDis<ret)
			{ 
				ret=getDis; 
				x=p[o[i]]; 
				y=p[o[i+j]]; 
			} 
		} 
	} 
	return ret; 
} 
int main() 
{
	int t;
	scanf("%d",&t);
	while(t--)
	{ 
		scanf("%d",&n);
		for(int i=1;i<=n;++i)
		{
			scanf("%lf%lf",&p[i].x,&p[i].y); 
			p[i].flag=0;
		}
		for(int i=n+1;i<=2*n;i++)
		{
			scanf("%lf%lf",&p[i].x,&p[i].y);
			p[i].flag=1;	
		}
		n=2*n;
		sort(p+1,p+n+1,cmp_x); 
		Point x,y; 
		double minDis=search(1,n,x,y); 
		printf("%.3lf\n",minDis); 
	} 
	return 0; 
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值