Cod sursa(job #2226470)

Utilizator georgerapeanuRapeanu George georgerapeanu Data 30 iulie 2018 11:22:19
Problema Cele mai apropiate puncte din plan Scor 75
Compilator cpp Status done
Runda Arhiva educationala Marime 6.85 kb
#include <cstdio>
#include <algorithm>
#include <cmath>
#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 < this->P){
            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 + sqrt(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 - sqrt(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;
}