首页 > 代码库 > bzoj 3053 HDU 4347 : The Closest M Points kd树
bzoj 3053 HDU 4347 : The Closest M Points kd树
bzoj 3053 HDU 4347 : The Closest M Points kd树
题目大意:求k维空间内某点的前k近的点。
就是一般的kd树,根据实测发现,kd树的两种建树方式,即按照方差较大的维度分开(建树常数大)或者每一位轮换分割(询问常数大),后者更快也更好些,以后就果断写第二种了。
#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>using namespace std;#define MAXN 510000#define MAXT MAXN#define MAXM 6#define sqr(x) ((qword)(x)*(x))#define INF 0x3f3f3f3ftypedef long long qword;int n,m;struct point{ int a[MAXM]; qword dis; void pm() { printf("(%d",a[0]); for (int i=1;i<m;i++) printf(",%d",a[i]); printf(")"); } void pm2() { for (int i=0;i<m-1;i++) printf("%d ",a[i]); printf("%d\n",a[m-1]); }}pl[MAXN];bool cmp_0(const point &p1,const point &p2){ return p1.a[0]<p2.a[0];}bool cmp_1(const point &p1,const point &p2){ return p1.a[1]<p2.a[1];}bool cmp_2(const point &p1,const point &p2){ return p1.a[2]<p2.a[2];}bool cmp_3(const point &p1,const point &p2){ return p1.a[3]<p2.a[3];}bool cmp_4(const point &p1,const point &p2){ return p1.a[4]<p2.a[4];}bool cmp_d(const point &p1,const point &p2){ return p1.dis<p2.dis;}struct kdt_node{ int a[MAXM]; int dd,mxp[MAXM],mnp[MAXM]; int ch[2]; int ptr;}kdt[MAXT];qword get_dis(point &pt,kdt_node &pn){ qword ret=0; for (int j=0;j<m;j++) if (pt.a[j]<pn.mnp[j] || pt.a[j]>pn.mxp[j]) ret+=min(sqr(pt.a[j]-pn.mxp[j]),sqr(pt.a[j]-pn.mnp[j])); return ret;}qword get_dis(point &p1,point &p2){ qword ret=0; for (int i=0;i<m;i++) ret+=sqr(p1.a[i]-p2.a[i]); return ret;}int topt=0;void Build_kdt(int &now,int l,int r,int d){ if (l>r)return; now=++topt; int i,j; for (j=0;j<m;j++)kdt[now].mxp[j]=-INF,kdt[now].mnp[j]=INF; for (i=l;i<=r;i++) for (j=0;j<m;j++) { kdt[now].mxp[j]=max(kdt[now].mxp[j],pl[i].a[j]); kdt[now].mnp[j]=min(kdt[now].mnp[j],pl[i].a[j]); }/* double ave[MAXM]; double sqv[MAXM]; memset(ave,0,sizeof(ave)); memset(sqv,0,sizeof(sqv)); for (i=l;i<=r;i++) for (j=0;j<m;j++) ave[j]+=pl[i].a[j]; for (j=0;j<m;j++) ave[j]/=(r-l+1); for (i=l;i<=r;i++) for (j=0;j<m;j++) sqv[j]+=sqr(pl[i].a[j]-ave[j]); kdt[now].dd=0; for (j=0;j<m;j++) if (sqv[j]>sqv[kdt[now].dd]) kdt[now].dd=j;*/ kdt[now].dd=d; switch (kdt[now].dd) { case 0:nth_element(&pl[l],&pl[(l+r)>>1],&pl[r+1],cmp_0);break; case 1:nth_element(&pl[l],&pl[(l+r)>>1],&pl[r+1],cmp_1);break; case 2:nth_element(&pl[l],&pl[(l+r)>>1],&pl[r+1],cmp_2);break; case 3:nth_element(&pl[l],&pl[(l+r)>>1],&pl[r+1],cmp_3);break; case 4:nth_element(&pl[l],&pl[(l+r)>>1],&pl[r+1],cmp_4);break; } kdt[now].ptr=(l+r)>>1; Build_kdt(kdt[now].ch[0],l,((r+l)>>1)-1,(d+1)%m); Build_kdt(kdt[now].ch[1],((r+l)>>1)+1,r,(d+1)%m);}point h[MAXN];int atot;int toph=0;void search_point(int now,point &pt){ if (!now)return ; qword cdis=get_dis(pt,pl[kdt[now].ptr]); if (toph<atot || cdis<h[0].dis) { if (toph==atot)pop_heap(&h[0],&h[toph--],cmp_d); h[toph]=pl[kdt[now].ptr]; h[toph].dis=cdis; push_heap(&h[0],&h[++toph],cmp_d); } int t; if (get_dis(pt,kdt[kdt[now].ch[0]]) < get_dis(pt,kdt[kdt[now].ch[1]])) t=0; else t=1; search_point(kdt[now].ch[t],pt); if (toph<atot || get_dis(pt,kdt[kdt[now].ch[t^1]]) < h[0].dis) { search_point(kdt[now].ch[t^1],pt); }}int main(){ // freopen("input.txt","r",stdin); //freopen("output.txt","w",stdout); int i,j,k,x,y,z; int root=0; while (~scanf("%d%d",&n,&m)) { for (i=0;i<n;i++) for (j=0;j<m;j++) scanf("%d",&pl[i].a[j]); Build_kdt(root,0,n-1,0); int q; scanf("%d",&q); point pt; for (i=0;i<q;i++) { for (j=0;j<m;j++) scanf("%d",&pt.a[j]); scanf("%d",&atot); search_point(root,pt); printf("the closest %d points are:\n",atot); while (toph) { pop_heap(&h[0],&h[toph--],cmp_d); } for (j=0;j<atot;j++) h[j].pm2(); } }}
bzoj 3053 HDU 4347 : The Closest M Points kd树
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。