import std.algorithm;
import std.array;
import std.ascii;
import std.container;
import std.conv;
import std.math;
import std.numeric;
import std.range;
import std.stdio;
import std.string;
import std.typecons;
void log(A...)(A arg) { stderr.writeln(arg); }
int size(T)(in T s) { return cast(int)s.length; }

immutable real EPS = 1e-7;

struct Point {
    real x, y;
    Point opBinary(string op)(in Point p) const if (op == "+" || op == "-") {
        return Point(mixin("x" ~ op ~ "p.x"), mixin("y" ~ op ~ "p.y"));
    }
    Point opBinary(string op)(real k) const if (op == "*" || op == "/") {
        return Point(mixin("x" ~ op ~ "k"), mixin("y" ~ op ~ "k"));
    }
};
real dot(in Point a, in Point b) { return a.x * b.x + a.y * b.y; }
real cross(in Point a, in Point b) { return a.x * b.y - a.y * b.x; }
real norm(in Point a) { return sqrt(dot(a, a)); }
Point rot90(in Point p) { return Point(-p.y, p.x); }
real angle(in Point a) { return atan2(a.y, a.x); }
bool approxEqual(in Point a, in Point b) { return abs(a.x - b.x) < EPS && abs(a.y - b.y) < EPS; }


int ccw(Point a, Point b, Point c){
    b = b - a; c = c - a;                                          
    if (cross(b, c) > EPS) return +1;     
    if (cross(b, c) < -EPS) return -1;    
    if (dot(b, c) < 0) return +2;         
    if (norm(b) < norm(c)) return -2;     
    return 0;                             
}

struct Line {
    Point a, b;
};
bool contains(in Line l, in Point p) { return ccw(l.a, l.b, p) % 2 == 0; }
bool parallel(in Line s, in Line t) { return abs(cross(s.b - s.a, t.b - t.a)) < EPS; }
bool equals(in Line s, in Line t) { return parallel(s, t) && contains(s, t.a); }

Point projection(in Line l, in Point p) {
    Point u = (p - l.a), v = (l.b - l.a);
    return l.a + (v / norm(v)) * (dot(u, v) / norm(v));
}

struct Segment {
    Point a, b;
};
bool intersects(in Segment s, in Segment t) {
    return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 && ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}
bool contains(in Segment s, in Point p) {
    return ccw(s.a, s.b, p) == 0;
}

void main() {
    int N;
    Point[] ps;
    void input() {
        readf("%d\n", &N);
        ps = new Point[N];
        foreach (i; 0 .. N) {
            real x, y; readf("%f %f\n", &x, &y);
            ps[i] = Point(x, y);
        }
    }

    void solve() {
        Point[] vs;
        int[] indices;
        for (int i = 0; i < N; i++) {
            indices ~= vs.size;
            auto a = ps[i];
            auto b = ps[(i + 1) % N];
            auto s = Segment(a, b);
            auto l = Line(a, b);
            Point[] us = [a];
            for (int j = 0; j < N; j++) {
                if (j == i || j == i + 1) continue;
                auto q = ps[j];
                auto proj = l.projection(q);
                if (s.contains(proj)) {
                    us ~= proj;
                }
            }
            us = us.sort!((x, y) => (x - a).norm < (y - a).norm).uniq!approxEqual.array;
            vs ~= us;
        }

        const infty = 1e10;
        int n = vs.size;
        real ans = infty;
        int next(int i) { return (i + 1) % n; }
        int prev(int i) { return (i + n - 1) % n; }
        //writeln("n: ", n);
        foreach (k; indices) {
            auto dp = new real[][](n, n);
            foreach (ref l; dp) l[] = infty;
            alias P = Tuple!(int, "i", int, "j");
            alias State = Tuple!(P, "v", real, "cost");
            BinaryHeap!(Array!State, "a.cost > b.cost") PQ;
            PQ.insert(State(P(k, prev(k)), (vs[k] - vs[prev(k)]).norm));
            dp[k][prev(k)] = (vs[k] - vs[prev(k)]).norm;
            while (! PQ.empty) {
                auto cur = PQ.front; PQ.removeFront;
                auto cur_i = cur.v.i;
                auto cur_j = cur.v.j;
                auto nexts = [
                    P(next(cur_i), cur_j),
                    P(cur_i, prev(cur_j)),
                    P(next(cur_i), prev(cur_j))
                ];
                auto costs = [
                    (vs[next(cur_i)] - vs[cur_j]).norm,
                    (vs[cur_i] - vs[prev(cur_j)]).norm,
                    (vs[next(cur_i)] - vs[prev(cur_j)]).norm
                ];
                foreach (idx, next_v; nexts) {
                    real cur_cost = costs[idx];
                    real ncost = max(cur.cost, cur_cost);
                    if (ncost >= ans) continue;
                    if (dp[next_v.i][next_v.j] > ncost) {
                        dp[next_v.i][next_v.j] = ncost;
                        if (next_v.i != next_v.j) {
                            PQ.insert(State(next_v, ncost));
                        }
                    }
                }
            }
            foreach (i; 0 .. n) {
                ans = min(ans, dp[i][i]);
            }
        }
        writefln("%.12f", ans);
    }

    input(); solve();
}