K-D树

#include <bits/stdc++.h>

using namespace std;

#define INT_INF 0x3fffffff

#define EPS 1e-12

#define MOD 1000000007

#define PI 3.141592653579798

#define N 60000

struct data{

    long long pos[10];

    int id;

} T[N] , op , point;

int split[N],demension,now,n;

bool use[N];              

long long id,ans;      

double var[10];        

bool cmp(data a,data b){

    return a.pos[split[now]]<b.pos[split[now]];

}

void build(int L,int R){

    if(L>R) return;

    int mid=(L+R)>>1;

    for(int pos=0;pos<demension;pos++){

        double ave=var[pos]=0.0;

        for(int i=L;i<=R;i++)

            ave+=T[i].pos[pos];

        ave/=(R-L+1);

        for(int i=L;i<=R;i++)

var[pos]+=(T[i].pos[pos]-ave)*(T[i].pos[pos]-ave);

        var[pos]/=(R-L+1);

    }

split[now=mid]=0;

    for(int i=1;i<demension;i++)

        if(var[split[mid]]<var[i]) split[mid]=i;

    nth_element(T+L,T+mid,T+R+1,cmp);

build(L,mid-1);

build(mid+1,R);

}

void query(int L,int R){

    if(L>R) return;

    int mid=(L+R)>>1;

    long long dis=0;

    for(int i=0;i<demension;i++)

dis+=(op.pos[i]-T[mid].pos[i])*(op.pos[i]-T[mid].pos[i]);

if(!use[T[mid].id] && dis<ans){

K-D树

in      2 2 (2个二维点)       out

0 0                                   the closest 1

1 1                                   points are:

1       (1个询问)            1 1

3 3 (询问点)

1   (求最近1个点)

//pos[10]维度,id编号

//T[N] 树中的结点

//op当前要查询的结点(坐标)

//point取得最近距离下的点

//分裂方式,维度,半点数,总点数

//已使用数组

//最近结点值及到分裂点距

//各维度方差存储数组

 

 

 

 

//区间为空则跳出

//取区间中点

//求出 每一维 上面的方差

//初始化VAR与平均值为0

 

//求此维度和

//求此维度平均值

 

//求此维度方差未平均

//求此维度方差

 

//半点数NOW用于后面排序,的确是从中间的点进宪分裂

//找到方差最大的那一维,用它来作为当前区间的 split_method

//排第MID元素排到第MID的位置

//对左儿子建树

//对右儿子建树

 

//区间为空退出查询

//求中点编号

 

//求出目标点 op 到现在的根节点(分裂点)的距离

//根结点可用且ans可更新

        ans=dis; 

        point=T[mid]; 

        id=T[mid].id; 

    }

long long radius=

(op.pos[split[mid]]-T[mid].pos[split[mid]])*

(op.pos[split[mid]]-T[mid].pos[split[mid]]);

    if(op.pos[split[mid]]<T[mid].pos[split[mid]]){

        query(L,mid-1);

        if(radius<=ans) query(mid+1,R);

    }else{

        query(mid+1,R);

        if(radius<=ans) query(L,mid-1);

    }

}

int main(){

    while(scanf("%d%d",&n,&demension)!=EOF){

        for(int i=1;i<=n;i++){

            for(int j=0;j<demension;j++)

                scanf("%I64d",&T[i].pos[j]);

            T[i].id=i;

        }

        build(1,n);

        int m,q; scanf("%d",&q);

        while(q--){

            memset(use,0,sizeof(use));

            for(int i=0;i<demension;i++)

                scanf("%I64d",&op.pos[i]);

            scanf("%d",&m);

            printf("the closest %d points are:\n",m);

            while(m--){

                ans=(((long long)INT_INF)*INT_INF);

                query(1,n);

                for(int i=0;i<demension;i++){

                    printf("%I64d",point.pos[i]);

                    if(i==demension-1) printf("\n");

                    else printf(" ");

                }

                use[id]=1;

            }

        }

    }

    return 0;

}

//更新最近距离

//更新取得最近距离下的点

//更新取得最近距离的点的 id

 

//计算 op 到分裂平面的距离的平方(当前要查询的点到当前点集的中间点之差的平方)

//对子区间进行查询,小于则在左子树,大于则在右子树查,但是若到平面距小于等于到分裂点距则也要考虑另一边

 

 

 

 

 

//确定要输出多少个点及维度

 

 

//读入 n 个点

//记录本结点的编号,二叉树的结点就反映了父亲与儿子的关系

//建树

// q 个询问

 

 

 

//输入所要查询的点

 

//求到所给点最近的M个点

//(查一个删一个)

//初始化无限大

//询问一次

 

//把询问所得到的点逐维度输出

//简单的换行与空格

 

 

//此结点已使用

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值