#include #include #include #include #include #define repi(i,a,b) for(int i=(a);i<(b);++i) #define rep(i,a) repi(i,0,a) #define repd(i,a) for(int i=(a);i>=0;--i) #define all(a) (a).begin(), (a).end() #define itri(it,a,b) for(auto it=(a);it!=(b);++it) #define itr(it,a) for(auto it=(a).begin();it!=(a).end();++it) const int MAX_N = 120000; struct UnionFind { std::vector par, rank; UnionFind( std::size_t sz ) : par(sz), rank(sz) { std::iota( all(par), 0 ); } int find( int x ) { return x==par[x]?x:par[x]=find(par[x]); } void unite( int x, int y ) { x = find(x); y = find(y); if( x == y ) return; if( rank[x] < rank[y] ) par[x] = y; else { par[y] = x; if( rank[x] == rank[y] ) ++rank[x]; } return; } bool same( int x, int y ) { return find(x)==find(y); } }; struct Pt { double x, y; Pt() : x(0), y(0) {} Pt( double x, double y ) : x(x), y(y) {} Pt operator+ ( const Pt &pt ) const { return Pt( x+pt.x, y+pt.y ); } Pt operator- ( const Pt &pt ) const { return Pt( x-pt.x, y-pt.y ); } Pt operator* ( double k ) const { return Pt( k*x, k*y ); } bool operator< ( const Pt &pt ) const { if( x == pt.x ) return y < pt.y; return x < pt.x; } double dot( const Pt &pt ) const { return x*pt.x+y*pt.y; } double cross( const Pt &pt ) const { return x*pt.y-y*pt.x; } }; int N; std::vector convex_hull( const std::vector &pts ) { if( pts.size() <= 2 ) { std::vector ret; if( pts.size() >= 1 ) ret.push_back(0); else if( pts.size() == 2 ) ret.push_back(1); return ret; } std::vector > sorted; rep( i, pts.size() ) sorted.push_back( std::make_pair( pts[i], i ) ); std::sort( all(sorted) ); int k = 0; std::vector ret( 2*pts.size() ); rep( i, pts.size() ) { while( k>1 && (pts[ret[k-1]]-pts[ret[k-2]]).cross(sorted[i].first-pts[ret[k-1]]) <= 0 ) --k; ret[k++] = sorted[i].second; } int t = k; repd( i, pts.size()-2 ) { while( k>t && (pts[ret[k-1]]-pts[ret[k-2]]).cross(sorted[i].first-pts[ret[k-1]]) <= 0 ) --k; ret[k++] = sorted[i].second; } ret.resize( k-1 ); return ret; } int sqr( int x ) { return x*x; } int X[MAX_N+1], Y[MAX_N+1]; std::map pts[20015]; std::vector m[MAX_N+1]; int main() { scanf( "%d", &N ); rep( i, N ) { scanf( "%d%d", X+i, Y+i ); pts[X[i]+=10001][Y[i]+=10001] = i; } UnionFind uf( N ); rep( x, 20002 ) itr( it, pts[x] ) { auto it2 = it; for( it2++; it2 != pts[x].end(); ++it2 ) { if( it2->first-it->first > 10 ) break; uf.unite( it->second, it2->second ); } repi( x2, x+1, x+11 ) itri( it2, pts[x2].lower_bound( it->first-10 ), pts[x2].end() ) { if( it2->firstfirst && sqr(x2-x)+sqr(it2->first-it->first) > 100 ) continue; if( sqr(x2-x)+sqr(it2->first-it->first) > 100 ) break; uf.unite( it->second, it2->second ); } } rep( i, N ) m[uf.find(i)].push_back( Pt( X[i], Y[i] ) ); double ans = 1; rep( i, N ) if( !m[i].empty() ) { auto msz = m[i].size(); if( msz == 1 ) ans = std::max( ans, 2.0 ); else if( msz == 2 ) ans = std::max( ans, 2+sqrt((m[i][1]-m[i][0]).dot(m[i][1]-m[i][0])) ); else { auto chpts = convex_hull( m[i] ); rep( j, chpts.size() ) rep( k, j ) ans = std::max( ans, 2+sqrt((m[i][chpts[k]]-m[i][chpts[j]]).dot(m[i][chpts[k]]-m[i][chpts[j]])) ); } } printf( "%.9f\n", ans ); return 0; }