zoj 2107

       这题做了很久,一直都是1秒多,真不知道他们300ms是怎么做出来的。看了网上的代码,大部分都是O(nlgnlgn),于是绞尽脑汁,写了个O(nlgn)的代码,但是时间上没有显著地提高。

/**
 *  O(nlogn)
 *  zoj_2107
 **/
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;

int const MAXN = 100010;
double const eps = 1e-20;

struct Point {
	double x, y;
};
int n;
Point toy[MAXN];
int yarr[MAXN];
int buffer[2*MAXN];

inline bool Dxlessy( double x, double y ) {
	return x+eps < y;
}
inline bool Dxequaly( double x, double y ) {
	return fabs(x-y)<eps;
}
inline double Dmin( double x, double y ) {
	if ( Dxlessy( x, y ) )
		return x;
	return y;
}
bool pcmp( Point const& pa, Point const& pb ) {
	if ( Dxlessy( pa.x, pb.x ) )
		return true;
	if ( Dxequaly( pa.x, pb.x ) && Dxlessy( pa.y, pb.y ) )
		return true;
	return false;
}
bool ycmp( int a, int b ) {
	if ( Dxlessy( toy[a].y, toy[b].y ) )
		return true;
	if ( Dxequaly( toy[a].y, toy[b].y ) && Dxlessy( toy[a].x, toy[b].x ) )
		return true;
	return false;
}
inline double PointDist( Point const& a, Point const& b ) {
	return sqrt( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) );
}

double NearestP( int start, int end, int begin ) {
	int cnt = end-start+1;
	double dist;
	if ( 2 == cnt ) {
		return PointDist( toy[start], toy[end] );
	}
	if ( 3 == cnt ) {
		dist = Dmin( PointDist( toy[start], toy[start+1] ), PointDist( toy[start+1], toy[end] ) );
		dist = Dmin( dist, PointDist( toy[start], toy[end] ) );
		return dist;
	}

	int le, i, j, a, b, k;
	double x0, d1, d2;
	
	le = start+(cnt>>1)-1;
	x0 = toy[le].x;
	
	a = start;
	b = le+1;
	for ( i = begin; i < begin+cnt; ++ i ) {
		if ( buffer[i] <= le ) //left part
			yarr[a++] = buffer[i];
		else
			yarr[b++] = buffer[i];
	}

	memcpy( buffer+begin+cnt, yarr+start, (cnt>>1)*sizeof(int) );
	d1 = NearestP( start, le, begin+cnt );  //yarr[ start, le ]
	if ( d1 < eps )
		return 0.0;

	memcpy( buffer+begin+cnt, yarr+le+1, (cnt-(cnt>>1))*sizeof(int) );
	d2 = NearestP( le+1, end, begin+cnt );  //yarr[ le+1, end ]
	if ( d2 < eps )
		return 0.0;

	dist = Dmin( d1, d2 );
	
	a = start;
	for ( i = begin; i < begin+cnt; ++ i ) {
		if ( !Dxlessy( toy[ buffer[i] ].x, x0-dist )		
			&&  !Dxlessy( x0+dist, toy[ buffer[i] ].x ) )  
			yarr[a++] = buffer[i];
	}
	for ( i = start; i < a-1; ++ i ) {
		b = i+8>a ? a : i+8;
		for ( j = i+1; j < b; ++ j ) {
			dist = Dmin( dist, PointDist( toy[ yarr[i] ], toy[ yarr[j] ] ) );
		}
	}

	return dist;
}

int main()
{
	int i;
	double result;
	while ( scanf("%d", &n) != EOF ) {
		if ( 0 == n ) 
			break;
		for ( i = 0; i < n; ++ i ) {
			scanf("%lf%lf", &toy[i].x, &toy[i].y );
			buffer[i] = i;
		}

		sort( toy, toy+n, pcmp );
		sort( buffer, buffer+n, ycmp );

		result = NearestP( 0, n-1, 0 );

		printf("%.2lf\n", result/2.0);
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值