HDU 4347 The Closest M Points KD-tree

Problem Description
The course of Software Design and Development Practice is objectionable. ZLC is facing a serious problem .There are many points in K-dimensional space .Given a point. ZLC need to find out the closest m points. Euclidean distance is used as the distance metric between two points. The Euclidean distance between points p and q is the length of the line segment connecting them.In Cartesian coordinates, if p = (p1, p2,..., pn) and q = (q1, q2,..., qn) are two points in Euclidean n-space, then the distance from p to q, or from q to p is given by:

Can you help him solve this problem?
 

Input
In the first line of the text file .there are two non-negative integers n and K. They denote respectively: the number of points, 1 <= n <= 50000, and the number of Dimensions,1 <= K <= 5. In each of the following n lines there is written k integers, representing the coordinates of a point. This followed by a line with one positive integer t, representing the number of queries,1 <= t <=10000.each query contains two lines. The k integers in the first line represent the given point. In the second line, there is one integer m, the number of closest points you should find,1 <= m <=10. The absolute value of all the coordinates will not be more than 10000.
There are multiple test cases. Process to end of file.
 

Output
For each query, output m+1 lines:
The first line saying :”the closest m points are:” where m is the number of the points.
The following m lines representing m points ,in accordance with the order from near to far
It is guaranteed that the answer can only be formed in one ways. The distances from the given point to all the nearest m+1 points are different. That means input like this:
2 2
1 1
3 3
1
2 2
1
will not exist.
 

Sample Input
  
  
3 2 1 1 1 3 3 4 2 2 3 2 2 3 1
 

Sample Output
  
  
the closest 2 points are: 1 3 3 4 the closest 1 points are: 1 3
 

Author
HIT
 

Source
 

Recommend





题目大意:给出n个K维的点,然后t条询问,每次询问给出一个K维的点x,
让你每次求出离x最近的m个点。

kd-tree的模板题目……
注意一下kd-tree的构建之中,需要找到一个维度来划分两部分,
那么应该选择哪一个呢?为了两边尽量均衡,我们选择方差最小的维度。
那么选择的应该是哪一个点作为中间点呢?
很容易想到,选择中位数。
求中位数一开始,我一开始用了sort(好蠢……)
这样的话build就平白无故多log了……
直接用nth_element!

用法:nth_element(a+L,a+mid,a+R+1,cmp)
a数组,对于[L,R]的区间,mid=(L+R)>>1,
那么按照cmp里面(和sort写法一致)的规则,
比如cmp里面是a[x]<a[y] return true,也就是从小到大,
那么将会把比a[mid]小的所有数移到mid的左边,比a[mid]大的移到右边。
其实我们是可以手写nth_element的,也就是快排里面的part……
平均时间复杂度O(N)。

hdu的评测机很不稳定啊……
一份代码,提交三次,最大时间起伏到了1000ms!



#include<bits/stdc++.h>
#define ll long long
using namespace std;
int read(){
    int x=0,f=1;char ch=getchar();
    while (ch<'0' || ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int 
	N=50005,
	K=10;
const ll 
	inf=(ll)1000000000;

int n,Dimension,t;
int split[N];
ll ans;
bool used[N];
double var[K];
struct POINT{
	int Dim[K],id;
}point[N],T,ANS;
bool cmp(POINT x,POINT y){
	return x.Dim[split[t]]<y.Dim[split[t]];
}
void build(int L,int R){
	if (L>R) return;
	int mid=(L+R)>>1;
	t=mid;
	double avg,len=(double)(R-L+1);
	
	split[mid]=0,var[0]=-1.0;
	for (int i=1;i<=Dimension;i++){
		avg=var[i]=0.0;
		for (int j=L;j<=R;j++) avg+=point[j].Dim[i];
		avg/=len;
		for (int j=L;j<=R;j++)
			var[i]+=((double)point[j].Dim[i]-avg)*((double)point[j].Dim[i]-avg);
		var[i]/=len;
		if (var[split[mid]]<var[i]) split[mid]=i;
	}
	
	nth_element(point+L,point+mid,point+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;
	ll tmp=(ll)0;
	for (int i=1;i<=Dimension;i++)
		tmp+=(ll)(point[mid].Dim[i]-T.Dim[i])*(ll)(point[mid].Dim[i]-T.Dim[i]);
	
	if (!used[point[mid].id] && ans>tmp)
		ans=tmp,ANS=point[mid];
	
	ll radius=(ll)(T.Dim[split[mid]]-point[mid].Dim[split[mid]])*
			(ll)(T.Dim[split[mid]]-point[mid].Dim[split[mid]]);
	if (T.Dim[split[mid]]<=point[mid].Dim[split[mid]]){
		query(L,mid-1);
		if (ans>=radius) query(mid+1,R);
	}	else{
		query(mid+1,R);
		if (ans>=radius) query(L,mid-1);
	}
}
void solve(){
	for (int i=1;i<=n;i++){
		point[i].id=i;
		for (int j=1;j<=Dimension;j++)
			point[i].Dim[j]=read();
	}
	build(1,n);
	
	int m=read(),num;
	while (m--){
		for (int i=1;i<=Dimension;i++)
			T.Dim[i]=read();
		num=read();
		printf("the closest %d points are:\n",num);
		memset(used,0,sizeof(used));
		while (num--){
			ans=inf;
			query(1,n);
			for (int i=1;i<Dimension;i++)
				printf("%d ",ANS.Dim[i]);
			printf("%d\n",ANS.Dim[Dimension]);
			used[ANS.id]=1;
		}
	}
}
int main(){
	while (~scanf("%d%d",&n,&Dimension))
		solve();
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值