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

来源:互联网 发布:教学视频录制软件 编辑:程序博客网 时间:2024/06/03 14:54
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;}





1 0
原创粉丝点击