Cod sursa(job #2226397)

Utilizator georgerapeanuRapeanu George georgerapeanu Data 30 iulie 2018 10:21:30
Problema Cele mai apropiate puncte din plan Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 5.48 kb
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cassert>

using namespace std;

struct point_data_t{
	double x,y;
	
	point_data_t(){
		x = y = 0;
	}
	
	point_data_t(double x,double y){
		this->x = x;
		this->y = y;
	}
	
	double sqr_len(){
		return x * x + y * y; 
	}
	
	double len(){
		return sqrt(sqr_len());
	}
	
	point_data_t operator - (point_data_t &other)const{
		return point_data_t(x - other.x,y - other.y);
	}
	
	bool operator < (const point_data_t &other)const{
		if(x != other.x){
			return x < other.x;
		}
		return y < other.y;
	}
	
	bool operator == (const point_data_t &other)const{
		return x == other.x && y == other.y;
	}
	
	bool operator != (const point_data_t &other)const{
		return x != other.x || y != other.y;
	}
};

class KDTree{
private:
	KDTree *leftson,*rightson;
	bool split_direction;
	point_data_t P;
public:
	
	KDTree(){
		leftson = rightson = NULL;
		split_direction = 0;
		P = point_data_t(0,0);
	}
	
	~KDTree(){
		if(leftson != NULL){
			delete leftson;
		}
		
		if(rightson != NULL){
			delete rightson;
		}
	}
	
	KDTree(KDTree *leftson,KDTree *rightson,bool split_direction,point_data_t P){
		this->leftson = leftson;
		this->rightson = rightson;
		this->split_direction = split_direction;
		this->P = P;
	}
	
	void build(vector<point_data_t> &points,int left,int right,bool split_direction){///[left,right);swaps x and y of points to prevent two compare functions;leaves points parameter uneffected
		int mid = (left + right) / 2;
		nth_element(points.begin() + left,points.begin() + mid,points.begin() + right);
		
		this->P = points[mid];
		this->split_direction = split_direction;
		
		for(int i = left;i < right;i++){
			swap(points[i].x,points[i].y);
		}
		
		if(left < mid){
			this->leftson = new KDTree;
			this->leftson->build(points,left,mid,split_direction ^ 1);
		}
		
		if(mid + 1 < right){
			this->rightson = new KDTree;
			this->rightson->build(points,mid + 1,right,split_direction ^ 1);
		}
		
		for(int i = left;i < right;i++){
			swap(points[i].x,points[i].y);
		}
	}
	///best_dist_so_far contains the actual distance squared;leaves P uneffected,returns the closeste point
	point_data_t find_nearest_neighbour(point_data_t &P,double &best_dist_so_far){///P has the coordonates in order for this depth,returns the answer with coordinates swaped depending on the depth
		
		point_data_t best_subtree_point = this->P;
		
		if(this->P != P && best_dist_so_far > (this->P - P).sqr_len()){
			best_dist_so_far = (this->P - P).sqr_len();
			best_subtree_point = this->P;
		}
		
		if(leftson == NULL && rightson == NULL){
			return best_subtree_point;
		}
		
		if(leftson == NULL){
			
			swap(P.x,P.y);
			point_data_t rightson_ans = this->rightson->find_nearest_neighbour(P,best_dist_so_far);
			swap(P.x,P.y);
			swap(rightson_ans.x,rightson_ans.y);
			
			if((P - best_subtree_point).sqr_len() > (P - rightson_ans).sqr_len()){
				best_subtree_point = rightson_ans;
			}
			return best_subtree_point;
		}
		
		if(rightson == NULL){
			swap(P.x,P.y);
			point_data_t leftson_ans = this->leftson->find_nearest_neighbour(P,best_dist_so_far);
			swap(P.x,P.y);
			swap(leftson_ans.x,leftson_ans.y);
			
			if((P - best_subtree_point).sqr_len() > (P - leftson_ans).sqr_len()){
				best_subtree_point = leftson_ans;
			}
			return best_subtree_point;
		}			
		
		if(P.x < this->P.x){
			swap(P.x,P.y);
			point_data_t leftson_ans = this->leftson->find_nearest_neighbour(P,best_dist_so_far);
			swap(P.x,P.y);
			swap(leftson_ans.x,leftson_ans.y);
			
			if((P - best_subtree_point).sqr_len() > (P - leftson_ans).sqr_len()){
				best_subtree_point = leftson_ans;
			}
			
			if(P.x + best_dist_so_far >= this->P.x){
				swap(P.x,P.y);
				point_data_t rightson_ans = this->rightson->find_nearest_neighbour(P,best_dist_so_far);
				swap(P.x,P.y);
				swap(rightson_ans.x,rightson_ans.y);
				
				if((P - best_subtree_point).sqr_len() > (P - rightson_ans).sqr_len()){
					best_subtree_point = rightson_ans;
				}
			}
			return best_subtree_point;
		}
		else{
			swap(P.x,P.y);
			point_data_t rightson_ans = this->rightson->find_nearest_neighbour(P,best_dist_so_far);
			swap(P.x,P.y);
			swap(rightson_ans.x,rightson_ans.y);
			
			if((P - best_subtree_point).sqr_len() > (P - rightson_ans).sqr_len()){
				best_subtree_point = rightson_ans;
			}
			
			if(P.x - best_dist_so_far <= this->P.x){
				swap(P.x,P.y);
				point_data_t leftson_ans = this->leftson->find_nearest_neighbour(P,best_dist_so_far);
				swap(P.x,P.y);
				swap(leftson_ans.x,leftson_ans.y);
				
				if((P - best_subtree_point).sqr_len() > (P - leftson_ans).sqr_len()){
					best_subtree_point = leftson_ans;
				}
			}
			return best_subtree_point;
		}
	}
	
	void print_tree(){
		///cout << this << " " << leftson << " " << rightson << " " << P.x << " " << P.y << " " << split_direction << "\n";
		
		if(leftson != NULL){
			this->leftson->print_tree();
		}
		
		if(rightson != NULL){
			this->rightson->print_tree();
		}
	}
};

int N;
vector<point_data_t> V;
FILE *f = fopen("cmap.in","r");
FILE *g = fopen("cmap.out","w");

int main(){

	fscanf(f,"%d",&N);
	V.resize(N);
	for(int i = 0;i < N;i++){
		fscanf(f,"%lf %lf",&V[i].x,&V[i].y);
	}
	
	KDTree *root = new KDTree;
	root->build(V,0,N,0);
	double ans = 5e18;
	
	for(auto it:V){
		root->find_nearest_neighbour(it,ans);
	}
	
	fprintf(g,"%.7f",sqrt(ans));
	
	fclose(f);
	fclose(g);
	
	return 0;
}