POJ 3714 Raid

题意是平面上有一堆站点与士兵,要求士兵与站点最近的距离是多少。

本题为一道分治经典例题最近点对的问题的变形,需要添加条件是两点必须不属于同一集合即分属于站点与士兵。

求解最近点对问题的思路通常为分治。

不断地向下dfs,将原集合分为两份。现在点之间的距离便有了两种情况,第一种为同在一边可以进行递归处理。第二种为一个在左边,一个在右边。为了简化我们的时间复杂度,我们可以先算出这两边的最小值,将左右两边距离在这最小值之内的点存下来,进行暴力枚举计算距离,对于本题便可以AC。

下附AC代码。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#define maxn 200005
using namespace std;
int n; 
int temp[maxn];
struct p
{
	double x,y,flag;
}pos[maxn];
double myabs(double now)
{
	return now>=0 ? now :-now;
}
bool operator <(p x,p y)
{
	if(x.x!=y.x)
	return x.x<y.x;
	return x.y<y.y;
}
double dis(int l,int r)
{
	return sqrt((pos[l].x-pos[r].x )*(pos[l].x-pos[r].x)+( pos[l].y-pos[r].y)*( pos[l].y-pos[r].y));
}
bool cmp(int i,int j)
{
	return pos[i].y<pos[j].y;
}
double dfs(int l,int r) 
{
	double now=98765432187654321;
	if(l==r)
	return now;
	if(l+1==r)
	{
		if(pos[l].flag==pos[r].flag)
		return now;
		else 
		return dis(l,r);
	}
	
	int mid=(l+r)/2;
	double ans1=dfs(l,mid);
	double ans2=dfs(mid+1,r);
	now=min(ans1,ans2);
	
	int cnt=0; 
	for(int i=l;i<=r;i++)
	{
		if(myabs(pos[i].x-pos[mid].x)<now)
		{
			temp[++cnt]=i;
		}
	}
	
	sort(temp+1,temp+1+cnt,cmp);
	
	for(int i=1;i<=cnt;i++)
	for(int j=i+1;j<=cnt;j++)
	{
		if(myabs(pos[temp[i]].y-pos[temp[j]].y)>now)
		break;
		double d=dis(temp[i],temp[j]);
		if(d<now && pos[temp[i]].flag!=pos[temp[j]].flag)
		{
			now=d;
		}
	}
	return now;
} 
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		n*=2;
		for(int i=1;i<=n;i++)
		{
			scanf("%lf%lf",&pos[i].x,&pos[i].y);
			if(i<=n/2)
			pos[i].flag=1;
			else
			pos[i].flag=2;
		}
		sort(pos+1,pos+1+n);
		printf("%.3lf\n",dfs(1,n));
	}
} 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值