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)
}
}