UVA 10245 - The Closest Pair Problem

这题采用分割法,利用hash和二分的思想可以写出高效算法。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

const int size_n = 10000 + 100;

double a[size_n][2];
int cur;
const int h_size = 100001;
int h[size_n * 10];
int s[size_n][2];
unsigned long long s2[size_n];

double ebsp = 1e-4;

int f(double x , int n)
{
	cur = 1;
	memset(h , 0 , sizeof(h));
	double t = sqrt(0.5) * x; 
	int len = (int)(40001.1 / t) + 1;
	for(int i = 0 ; i < n ; ++i)
	{
		int tx = (int)(a[i][0] / t);
		int ty = (int)(a[i][1] / t);
		
		unsigned long long total = (unsigned long long)tx * len + ty;
		int index = (total) % h_size;
		s2[cur] = total;
		s[cur][1] = h[index];
		s[cur][0] = i;
		h[index] = cur;
		
		unsigned long long des = s2[cur];
		for(int k = s[cur++][1] ; k ; k = s[k][1])
		{
			if((s2[k] == des)) return 1;
		}
	}
	return 0;
}

int d[][2] = {{-3 , -3} , {-3 , -2} , {-3 , -1} , {-3 , 0} , {-3 , 1} , {-3 , 2} , {-3 , 3} ,
			  {-2 , -3} , {-2 , -2} , {-2 , -1} , {-2 , 0} , {-2 , 1} , {-2 , 2} , {-2 , 3} ,
			  {-1 , -3} , {-1 , -2} , {-1 , -1} , {-1 , 0} , {-1 , 1} , {-1 , 2} , {-1 , 3} ,
			  {0 , -3} , {0 , -2} , {0 , -1}                  , {0 , 1} , {0 , 2} , {0 , 3} ,
			  {1 , -3} , {1 , -2} , {1 , -1} , {1 , 0} , {1 , 1} , {1 , 2} , {1 , 3} ,
			  {2 , -3} , {2 , -2} , {2 , -1} , {2 , 0} , {2 , 1} , {2 , 2} , {2 , 3} ,
			  {3 , -3} , {3 , -2} , {3 , -1} , {3 , 0} , {3 , 1} , {3 , 2} , {3 , 3}};
			  
double g(double dis , int n)
{
	double t = sqrt(0.5) * dis;
	int  len = (int)(40001.1 / t) + 1;
	double min_r = 10000;
	
	for(int i = 0 ; i < n ; ++i)
	{
		int x = (int)(a[i][0] / t);
		int y = (int)(a[i][1] / t);
		
		for(int j = 0 ; j < 48 ; ++j)
		{
			int tx = x + d[j][0];
			if(tx < 0 || tx >= len) continue;
			
			int ty = y + d[j][1];
			if(ty < 0 || tx >= len) continue;
			
			unsigned long long total = (unsigned long long)tx * len +  ty;
			int index = total % h_size;
			int r = h[index];
			for( ; r  ; r = s[r][1])
			{
				int tt = s[r][0];
				if(tt == i) continue;
				double tr = sqrt((a[i][0] - a[tt][0] ) * (a[i][0] - a[tt][0]) + (a[i][1] - a[tt][1]) * (a[i][1] - a[tt][1]));
				if(min_r > tr) min_r = tr;
			}
		}
	}
	return min_r;
}

int main()
{
	int n;
	while(scanf("%d" , &n) == 1 && n)
	{
		for(int i = 0 ; i < n ; ++i)
			scanf("%lf%lf" , a[i] , a[i] + 1);
			
		int r;
		double now = 20000;
		do{
			now /= 2;
			r = f(now , n);
			if(now < 1e-4) break;
		}while(r);
		double res;
		if(now < 1e-4) res = 0;
		else res = g(now , n);
		if(res < 10000) printf("%.4f\n" , res);
		else printf("INFINITY\n");
	}
	return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值