← Home
package main

import (
	"bufio"
	"fmt"
	"math"
	"math/bits"
	"os"
	"sort"
)

const MaxEdges = 4950
const W = (MaxEdges + 63) / 64

type U128 struct {
	hi uint64
	lo uint64
}

type U192 struct {
	hi  uint64
	mid uint64
	lo  uint64
}

type Key struct {
	num U128
	den uint64
}

type Edge struct {
	u, v      int
	isNonTree bool
	coord     int
}

type Event struct {
	key     Key
	typ     uint8
	a, b, c int
}

type DSU struct {
	p  []int
	sz []int
}

func NewDSU(n int) *DSU {
	p := make([]int, n)
	sz := make([]int, n)
	for i := 0; i < n; i++ {
		p[i] = i
		sz[i] = 1
	}
	return &DSU{p: p, sz: sz}
}

func (d *DSU) Find(x int) int {
	for d.p[x] != x {
		d.p[x] = d.p[d.p[x]]
		x = d.p[x]
	}
	return x
}

func (d *DSU) Union(a, b int) bool {
	ra := d.Find(a)
	rb := d.Find(b)
	if ra == rb {
		return false
	}
	if d.sz[ra] < d.sz[rb] {
		ra, rb = rb, ra
	}
	d.p[rb] = ra
	d.sz[ra] += d.sz[rb]
	return true
}

func mul64to128(a, b uint64) U128 {
	hi, lo := bits.Mul64(a, b)
	return U128{hi: hi, lo: lo}
}

func mul128by64(u U128, v uint64) U192 {
	pHi, pLo := bits.Mul64(u.lo, v)
	qHi, qLo := bits.Mul64(u.hi, v)
	mid, carry := bits.Add64(pHi, qLo, 0)
	hi := qHi + carry
	return U192{hi: hi, mid: mid, lo: pLo}
}

func mul128by64to128(u U128, v uint64) U128 {
	w := mul128by64(u, v)
	return U128{hi: w.mid, lo: w.lo}
}

func cmp128(a, b U128) int {
	if a.hi != b.hi {
		if a.hi < b.hi {
			return -1
		}
		return 1
	}
	if a.lo != b.lo {
		if a.lo < b.lo {
			return -1
		}
		return 1
	}
	return 0
}

func cmpKey(a, b Key) int {
	if a.den == b.den {
		return cmp128(a.num, b.num)
	}
	x := mul128by64(a.num, b.den)
	y := mul128by64(b.num, a.den)
	if x.hi != y.hi {
		if x.hi < y.hi {
			return -1
		}
		return 1
	}
	if x.mid != y.mid {
		if x.mid < y.mid {
			return -1
		}
		return 1
	}
	if x.lo != y.lo {
		if x.lo < y.lo {
			return -1
		}
		return 1
	}
	return 0
}

var basis [MaxEdges][W]uint64
var hasBasis [MaxEdges]bool

func highestFrom(v *[W]uint64, startWord int) int {
	for i := startWord; i >= 0; i-- {
		x := v[i]
		if x != 0 {
			return i*64 + 63 - bits.LeadingZeros64(x)
		}
	}
	return -1
}

func addVec(ids []int) bool {
	if len(ids) == 0 {
		return false
	}
	var vec [W]uint64
	p := -1
	for _, id := range ids {
		vec[id>>6] ^= uint64(1) << uint(id&63)
		if id > p {
			p = id
		}
	}
	for p >= 0 {
		if !hasBasis[p] {
			hasBasis[p] = true
			basis[p] = vec
			return true
		}
		pw := p >> 6
		row := &basis[p]
		for i := 0; i <= pw; i++ {
			vec[i] ^= row[i]
		}
		p = highestFrom(&vec, pw)
	}
	return false
}

func keyToFloat(k Key) float64 {
	num := math.Ldexp(float64(k.num.hi), 64) + float64(k.num.lo)
	return num / float64(k.den)
}

func main() {
	in := bufio.NewReader(os.Stdin)
	out := bufio.NewWriter(os.Stdout)
	defer out.Flush()

	var n int
	fmt.Fscan(in, &n)

	var x, y [100]int64
	for i := 0; i < n; i++ {
		fmt.Fscan(in, &x[i], &y[i])
	}

	var pair [100][100]int
	for i := range pair {
		for j := range pair[i] {
			pair[i][j] = -1
		}
	}

	var dist2 [100][100]uint64
	edgeCap := n * (n - 1) / 2
	triCap := n * (n - 1) * (n - 2) / 6

	edges := make([]Edge, 0, edgeCap)
	events := make([]Event, 0, edgeCap+triCap)

	for i := 0; i < n; i++ {
		for j := i + 1; j < n; j++ {
			dx := x[i] - x[j]
			dy := y[i] - y[j]
			d2 := uint64(dx*dx + dy*dy)
			dist2[i][j] = d2
			dist2[j][i] = d2
			idx := len(edges)
			edges = append(edges, Edge{u: i, v: j, coord: -1})
			pair[i][j] = idx
			pair[j][i] = idx
			events = append(events, Event{
				key: Key{num: U128{hi: 0, lo: d2}, den: 1},
				typ: 0,
				a:   idx,
			})
		}
	}

	for i := 0; i < n; i++ {
		for j := i + 1; j < n; j++ {
			for k := j + 1; k < n; k++ {
				a2 := dist2[j][k]
				b2 := dist2[i][k]
				c2 := dist2[i][j]

				max2 := a2
				sumOther := b2 + c2
				if b2 > max2 {
					max2 = b2
					sumOther = a2 + c2
				}
				if c2 > max2 {
					max2 = c2
					sumOther = a2 + b2
				}

				var key Key
				if max2 >= sumOther {
					key = Key{num: U128{hi: 0, lo: max2}, den: 1}
				} else {
					cross := (x[j]-x[i])*(y[k]-y[i]) - (y[j]-y[i])*(x[k]-x[i])
					if cross < 0 {
						cross = -cross
					}
					num := mul128by64to128(mul64to128(a2, b2), c2)
					den := uint64(cross) * uint64(cross)
					key = Key{num: num, den: den}
				}

				events = append(events, Event{
					key: key,
					typ: 1,
					a:   pair[i][j],
					b:   pair[i][k],
					c:   pair[j][k],
				})
			}
		}
	}

	sort.Slice(events, func(i, j int) bool {
		c := cmpKey(events[i].key, events[j].key)
		if c != 0 {
			return c < 0
		}
		return events[i].typ < events[j].typ
	})

	dsu := NewDSU(n)
	nonTree := 0
	triRank := 0
	prevBeta := 0
	anyPositive := false
	var ansKey Key

	for i := 0; i < len(events); {
		j := i + 1
		for j < len(events) && cmpKey(events[j].key, events[i].key) == 0 {
			j++
		}

		for k := i; k < j; k++ {
			if events[k].typ == 0 {
				ei := events[k].a
				if !dsu.Union(edges[ei].u, edges[ei].v) {
					edges[ei].isNonTree = true
					edges[ei].coord = nonTree
					nonTree++
				}
			}
		}

		for k := i; k < j; k++ {
			if events[k].typ == 1 {
				var ids [3]int
				cnt := 0

				e1 := events[k].a
				if edges[e1].isNonTree {
					ids[cnt] = edges[e1].coord
					cnt++
				}
				e2 := events[k].b
				if edges[e2].isNonTree {
					ids[cnt] = edges[e2].coord
					cnt++
				}
				e3 := events[k].c
				if edges[e3].isNonTree {
					ids[cnt] = edges[e3].coord
					cnt++
				}

				if cnt > 0 && addVec(ids[:cnt]) {
					triRank++
				}
			}
		}

		beta := nonTree - triRank
		if prevBeta == 0 && beta > 0 {
			anyPositive = true
		}
		if prevBeta > 0 && beta == 0 {
			ansKey = events[i].key
		}
		prevBeta = beta
		i = j
	}

	if !anyPositive {
		fmt.Fprintln(out, -1)
	} else {
		ans := 0.5 * math.Sqrt(keyToFloat(ansKey))
		fmt.Fprintf(out, "%.10f\n", ans)
	}
}