平面最近点对【kd树初探】

本文介绍了一种使用k-d树解决二维空间中寻找最接近点的问题,并提供了完整的C++实现代码。通过递归构建k-d树并对每个点进行查询,找到离给定点最近的点。该方法适用于解决大规模数据集上的最近邻搜索问题。

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

Description
    给出n个点,每个点坐标为(xi,yi)。
    定义距离为D(A,B)=|xA-xB|+|yA-yB|
    求每个点到离它最近的点的距离


Input
    第一行为一个整数N
    接下来N行每行两个整数xi,yi,表示第i个点的坐标


Output
    输出N行,每一行为第i个点的最近距离


Sample Input
4
0 0
0 1
1 0
1 1


Sample Output
1
1
1
1


Range
20% 0<N<1001

100% 0<N<200001,0<xi,yi<10,000,001


引用一下http://www.cnblogs.com/snake-hand/archive/2012/08/13/2636236.html


2D 3D KD-tree


k-d树可以对k维空间进行划分。



这里我们只讨论2维情况,多维的思想类似,实现起来也相差无几。


每次选取一维(最好和之前的维度不同),找到它的中位数,以它为分割线把平面分割成2部分。

然后nth_element()一下,使对于当前维度左边都是比mid值小的,右边大的。

然后就递归


查询的时候要注意,以最近点对为例,

假设由一条竖直的线  . |     目标点在左边,先递归左边找到最近距离S,目标点当前维度坐标+S >分割线,说明右边可能会有一个点使得答案更优。


另外一边同理!



然后,就这道题而言,每个点离它最近的肯定是本身。就找离他最近的2个点,除去本身就是离它最近的点了!


在细节处理上有需要注意的地方,详情参考代码:


#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cstring>
#include<cstdlib>
using namespace std;
const int maxn=200000+20;
const int maxk=5;
int which,K;
int n;
int m;//平面最近m个点 
struct Point
{
	int x[maxk];
	bool operator<(const Point &p)const 
	{
		return x[which]<p.x[which];
	}
}x[maxn],aim,pr[maxn];
priority_queue<int>q;//保存最近距离 
int ans[5];
int dis(const Point &a,const Point &b)
{
	int len=0;
	for(int i=0;i<K;i++)len+=abs(a.x[i]-b.x[i]);
	return len;
}
void build(int l,int r,int dep)
{
	if(l>r)return ;
	int mid=(l+r)>>1;
	which=dep%K;
	nth_element(x+l,x+mid,x+r+1);
	build(l,mid-1,dep+1);
	build(mid+1,r,dep+1);
}
void query(int l,int r,int dep)
{
	if(l>r)return ;
	int mid=(l+r)>>1,loc=dep%K;
	int len=dis(x[mid],aim);
	if(q.size()<m)q.push(len);
	else if(len<q.top()){q.pop();q.push(len);}
	if(l<r)
	{
		if(aim.x[loc]<x[mid].x[loc])
		{
			query(l,mid-1,dep+1);
			if(q.size()<m||aim.x[loc]+q.top()>x[mid].x[loc])query(mid+1,r,dep+1); 
		}
		else 
		{
			query(mid+1,r,dep+1);
			if(q.size()<m||aim.x[loc]-q.top()<x[mid].x[loc])query(l,mid-1,dep+1);
		}
	}
}
int main()
{
	freopen("find.in","r",stdin);
	freopen("find.out","w",stdout);
	//转化为求平面最近2个点 
	K=2;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<K;j++)scanf("%d",&x[i].x[j]);
		pr[i]=x[i];
	}
	build(0,n-1,0);
	for(int t=0;t<n;t++)
	{
		for(int i=0;i<K;i++)aim.x[i]=pr[t].x[i];//x被重新排了序,所以造成了混乱,应该用之前的x
		//所以另外开个数组保存 
		m=2;
		while(!q.empty())q.pop();
		query(0,n-1,0);
		int cnt=0;
		while(!q.empty())
		{
			ans[cnt++]=q.top();
			q.pop();
		}
		printf("%d\n",ans[0]);
	}
	return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值