Cod sursa(job #451322)

Utilizator blasterzMircea Dima blasterz Data 9 mai 2010 13:53:39
Problema Cele mai apropiate puncte din plan Scor 20
Compilator cpp Status done
Runda Arhiva educationala Marime 8.49 kb
// timus 1369 kd-tree
	// @author: Mircea Dima
	
	//(c) Mircea Dima
	// KD-TREES
	// insert, sterge in complexitate O(logn)
	// query O(sqrt(n))
	
	#include <cstdio>
	#include <string>
	#include <cmath>
	#include <vector>
	#include <algorithm>
	#include <iostream>
	#include <cstdlib>
	#include <cassert>
	#define eps 1e-14
	#define N 100001	
	
	using namespace std;
	struct point { double x, y; int id;point(){}; point(double a, double b){x=a;y=b;};};
	
	struct cmp1
	{
		bool operator ()(const point &a, const point &b)const
		{
			if (a.x < b.x ) return 1;
			return 0;
		}
	};
	struct cmp2
	{
		bool operator ()(const point &a, const point &b)const
		{
			if (a.y < b.y ) return 1;
			return 0;
		}
	};
	
	
	
	int n,m;
	vector<int> sol;
	
	//#define distanta(a, b) ((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y))
	
	inline double distanta(point a, point b)
	{
		return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
	}
	
	
	struct nod 
	{
		double x, y;
		int id; 
		bool dir; 
		nod *l, *r;
		nod (){};
		nod (double _x, double _y, int _id, bool _dir, nod *_l, nod *_r)
		{
			x = _x;
			y = _y;
			id = _id;
			dir = _dir;
			l = _l;
			r = _r;
		};
	};
	// x,y coordonatele punctului dupa care se face taietura
	// dir = directia ( 1 = coordonata X, 0 = coordonata Y)
	// deleted = imi spune daca nodul l-am sters sau nu (pentru a face lazy deletion)
	typedef nod* kd;
	
	kd R,nil;
	
	inline void init()
	{
		nil=new nod;
		nil->l=nil->r=0;
		nil->x=nil->y=0.0;
		nil->dir=0;
		//nil->deleted=0;
		nil->id = 0;
		R=nil;
	}
	
	

	
	inline void insert(kd &n, point P,bool dir, int id)
	{
		if(n == nil)
		{
			n=new nod;
			n->l=n->r=nil;
			n->x=P.x;
			n->y=P.y;
			n->dir=dir;
			n->id = id;
			return;
		}
		
		if(n->dir == 1)
		{
			if(P.x < n->x) insert(n->l, P,dir^1, id);
			else  insert(n->r, P,dir^1, id);
		}
		else
		{
			if(P.y < n->y) insert(n->l,P,dir^1, id);
			else insert(n->r, P,dir^1, id);
		}
	
	}
	
	//nearest neighbor O(sqrt(n))
	int ids[4];
	int nid;
	
	double dist=0x3f3f3f3f;
	inline void find_pos(kd &n, point P)
	// caut dreptunghiul in care se afla punctul ...
	{
		if(n == nil) return;
		
		//printf ("%lf_%lf\n", n->x, n->y);
		if(n->dir == 1)
		{
			if(P.x < n->x) find_pos(n->l, P);
			else find_pos(n->r, P);
		}
		else
		{
			if(P.y  < n->y) find_pos(n->l, P);
			else find_pos(n->r, P);
		}
		
		double d =distanta(P, point(n->x, n->y)); 
		//if(n->deleted == 0)
		
		bool ok = 1;
		for (int i = 0; i < nid; ++i)
			if (ids[i] == n->id)
				ok = 0;
		if (ok)
		{
		//	printf ("___%lf %lf\n", d, dist);
		if(dist > d)
		{	
			dist=d;
		
			sol.clear (),
			sol.push_back (n->id);
	//	else if (fabs (dist - d) < eps)
	//			sol.push_back (n->id);
			
		}
		}
		
	}
	
	inline int intersect(double X0, double Y0, double X1, double Y1, point P, double R)
	// verific daca dreptunghiul (X0, Y0, X1, Y1) se interesecteaza cu cercul de centru P si raza R
	{
	//	if((P.x > X0 || fabs (P.x - X0) < eps) && (P.x < X1 || fabs (P.x - X1) < eps) && 
		//	(P.y > Y0 || fabs (P.y - Y0) < eps) && (P.y < Y1 || fabs (P.y - Y1) < eps)) return 1;
		
		if(P.x + eps > X0 && P.x - eps < X1 && P.y + eps > Y0 && P.y - eps < Y1) return 1;
		if(P.y + eps > Y0 && P.y - eps < Y1 && distanta(point(X0, P.y), P) - eps <R) return 1;
		if(P.y + eps > Y0 && P.y - eps <Y1 && distanta(point(X1, P.y), P) - eps < R) return 1;
		if(P.x + eps > X0 && P.x - eps <X1 && distanta(point(P.x, Y0), P) - eps < R) return 1;
		if(P.x + eps > X0 && P.x - eps <X1 && distanta(point(P.x, Y1), P) - eps <R)  return 1;
	
		if(distanta(point(X0, Y0), P) - eps < R) return 1;
		if(distanta(point(X1, Y0), P) - eps < R ) return 1;
		if(distanta(point(X0, Y1), P) - eps < R ) return 1;
		if(distanta(point(X1, Y1), P) - eps <R ) return 1;
	
		return 0;
	}
	inline int intersect2(double X0, double Y0, double X1, double Y1, point P, double R)
	// verific daca dreptunghiul (X0, Y0, X1, Y1) se interesecteaza cu cercul de centru P si raza R
	{
	//	if((P.x > X0 || fabs (P.x - X0) < eps) && (P.x < X1 || fabs (P.x - X1) < eps) && 
		//	(P.y > Y0 || fabs (P.y - Y0) < eps) && (P.y < Y1 || fabs (P.y - Y1) < eps)) return 1;
		
		if((P.x > X0 || fabs (P.x - X0) < eps) && (P.x  < X1 || fabs (P.x - X1) < eps) && 
			(P.y > Y0 || fabs (P.y - Y0) < eps) && (P.y  < Y1 || fabs (P.y -Y1) < eps)) return 1;
		
		if((P.y > Y0 || fabs (P.y - Y0) < eps) && (P.y  < Y1 || fabs (P.y - Y1) < eps)
			&& (distanta(point(X0, P.y), P)  < R ||  fabs (distanta(point(X0, P.y), P) - R) < eps)) return 1;
		
		if((P.y > Y0 || fabs (P.y - Y0) < eps) && (P.y  < Y1 || fabs (P.y - Y1) < eps)
			&& (distanta(point(X1, P.y), P)  < R  || fabs (distanta(point(X1, P.y), P) - R) < eps)) return 1;
		
		if((P.x > X0 || fabs (P.x - X0) < eps) && (P.x  < X1 || fabs (P.x - X1) < eps)
			&& (distanta(point(P.x, Y0), P)  < R || fabs (distanta (point (P.x, Y0), P) - R) < eps)) return 1;
		
		if((P.x > X0 || fabs (P.x - X0) < eps) && (P.x  < X1 || fabs (P.x - X1) < eps) 
			&& (distanta(point(P.x, Y1), P)  < R || fabs (distanta (point (P.x, Y1), P) - R) < eps))  return 1;
	
		if((distanta(point(X0, Y0), P)  < R) ||
			fabs (distanta (point (X0, Y0), P) - R) < eps)
			return 1;
			
		if(distanta(point(X1, Y0), P)  < R ||
			fabs (distanta (point (X1, Y0), P) - R) < eps) return 1;
		
		if(distanta(point(X0, Y1), P)  < R ||
			fabs (distanta (point (X0, Y1), P) - R) < eps) return 1;
		
		if(distanta(point(X1, Y1), P)  < R || 
			fabs (distanta (point (X1, Y1), P) - R) < eps) return 1;
	
		return 0;
	}

	
	inline void query(kd n,point P, double X0, double Y0, double X1, double Y1)
	// determina distanta pana la cel mai apropiat punct O(sqrt(n))
	{
		
		if(n == nil) return ;
		// daca dreptunghiul nodului curent nu se intersecteaza cu cercul format de 
		// punctul P si de raza dist (cea mai mica distanta pana in momentul curent)
		// nu mai verificam punctele din acest dreptunghi
		if(intersect(X0, Y0, X1, Y1, P, dist) == 0 )return;//&& (rand () &1)) return;
		
		//printf ("%lf %lf___\n", n->x, n->y);
		double d=distanta(P, point(n->x, n->y));
//		printf ("_%lf\n", d);
		//if(n->deleted == 0) 
		bool ok = 1;
		for (int i = 0; i < nid; ++i)
			if (n->id == ids[i])
				ok = 0;

		if (ok)
		{
	//		dist = dist;
			//fprintf (stderr,"%lf\n", dist);
			//printf ("%lf: %lf \n", d,dist);
		if(dist > d) 
			dist=d,
			sol.clear (),
			sol.push_back (n->id);
		else if (fabs (dist - d) < eps)
				sol.push_back (n->id),
				dist = d;
		}
		
		if( n->dir == 1)
		{
			query(n->l, P, X0, Y0,n->x, Y1);
			query(n->r, P,n->x,Y0, X1, Y1);
		}
		else
		{
			query(n->l, P, X0, Y0, X1, n->y);
			query(n->r ,P,X0, n->y, X1, Y1);		
		}
	}
	//end nearest neighbor
	
	
	void ino (kd n)
	{
		if (n == nil) return;
		ino (n->l);
		printf ("%lf %lf %d\n", n->x, n->y, n->id);
		ino (n->r);
	}
	point A[100001];
	point B[10001];
	int nA, nB;
	
	
	
	kd build (kd &n, int l, int r, bool dir)
	{
		//printf ("_%d %d\n", l,r);
		if (l >= r)
		{
			n = new nod;
			n->dir = dir;
			n->l = n->r = nil;
			n->id = A[l].id;
			n->x = A[l].x;
			n->y = A[l].y;
			return n;
		}
		
		
		if (dir)
			sort (A + l, A + r + 1, cmp1());
		else
			sort (A + l, A + r + 1, cmp2());
		
		int m = (r + l) / 2;
		
		if (dir)
			while (m > l && fabs (A[m].x - A[m-1].x) <eps) --m;
		else
			while (m > l && fabs (A[m].y - A[m-1].y) < eps) --m;
		
		kd t = new nod;
		t->dir = dir;
		t->id = A[m].id;
		t->x = A[m].x;
		t->y = A[m].y;
		
		
		t->l = l <= m - 1 ? build (t->l, l, m - 1 , dir ^1) : nil;
		t->r = m + 1 <= r ? build (t->r, m + 1, r , dir ^1) : nil;
		
			
		return t;
		
		
	}
	
	
	int main( )
	{
		
		srand (6626013);
		init();
		
	//	freopen (args[1], "r", stdin);
		freopen ("cmap.in","r",stdin);
		freopen ("cmap.out", "w", stdout);	

	
		//scanf(" %d ", &nA);
			
		int i;
		int j;
		int idd;
		//for (i = 1; i <= nA; ++i)
		
		scanf ("%d\n", &nA);
		while (!feof (stdin))
		{
			++nA;
			i = nA;
			//cin >> idd >>  A[i].x >> A[i].y;
			scanf (" %lf %lf ",&A[i].x, &A[i].y);
			A[i].id = idd;
		}
		
	
		
		R = build (R, 1, nA, 1);
		//ino (R);
	
			

		double Sol = 1e20;
		double x0, y0;
		for (i = 1; i <= nA; ++i)
		{
			nid = 0;
			sol.clear ();
			x0 = A[i].x;
			y0 = A[i].y;
			dist=1e20;//0x3f3f3f3f;
			//printf ("_%lf\n", dist);
//			printf ("%lf %lf\n", x0, y0);
			
			ids[nid++] = A[i].id;
			//printf ("%d ", A[i].id);
	//		for (int j = 0; j < nid; ++j)
	//			printf ("%d ", ids[j]);
	//		printf("\n");
			find_pos(R, point(x0, y0));
			//printf ("_%lf\n", dist);
		//	printf ("tacu\n");
			query(R, point(x0, y0), -1000000001.0, -1000000001.0, 1000000001.0,1000000001.0);			
	
			assert (sol.size () != 0);	
//			printf ("%d\n", sol.size ());
		
			if (Sol > dist)
				Sol = dist;
		}
	
	printf ("%lf\n", Sol);	
		return 0;
	}