#include #include #include #include #include #include using namespace std; double dijkstra(int begin, int end, const vector > > &neighbors) { const int V = neighbors.size(); priority_queue > q; map potential; q.push(make_pair(-0, begin)); while (!q.empty()) { pair c = q.top(); q.pop(); if (potential.count(c.second)) continue; if (c.second == end) return -c.first; potential[c.second] = -c.first; const vector > &n = neighbors[c.second]; for (int i = 0; i < n.size(); i++) if (!potential.count(n[i].first)) q.push(make_pair(c.first - n[i].second, n[i].first)); } return HUGE_VAL; } typedef complex V2; const double EPS = 1e-12; V2 normalize(V2 v) { return v / abs(v); } double det(V2 u, V2 v) { return imag(conj(u) * v); } double get_point_line_distance(V2 p, V2 a, V2 b) { p -= a; b -= a; return det(b, p) / abs(b); } // 直線 pq, rs の交点を返す。二直線が平行なときは (NaN, NaN)。 V2 get_lines_intersection(V2 p, V2 q, V2 r, V2 s) { double a = get_point_line_distance(p, r, s); double b = get_point_line_distance(q, r, s); return (-b * p + a * q) / (a - b); } // 点 p が線分 ab から距離 EPS 未満にあるときに限り true を返す。 bool on_segment(V2 p, V2 a, V2 b) { if (abs(p - a) < EPS || abs(p - b) < EPS) return true; if (abs(get_point_line_distance(p, a, b)) >= EPS) return false; b -= a; p -= a; p /= normalize(b); return 0 <= real(p) && real(p) <= abs(b); } bool segments_intersect(V2 p, V2 q, V2 r, V2 s) { V2 i = get_lines_intersection(p, q, r, s); return on_segment(i, p, q) && on_segment(i, r, s); } double solve(const vector &hedge) { // 頂点集合作成 vector points, original; points.push_back(hedge.front()); original.push_back(hedge.front()); points.push_back(hedge.back()); original.push_back(hedge.back()); for (int i = 1; i < hedge.size() - 1; i++) { // 塀の各側に微小距離だけずらして二点を配置 const static double DELTA = 1e-9; V2 u = hedge[i-1] - hedge[i]; V2 v = hedge[i+1] - hedge[i]; V2 d = polar(DELTA, arg(u) + arg(v/u) / 2); points.push_back(hedge[i] + d); original.push_back(hedge[i]); points.push_back(hedge[i] - d); original.push_back(hedge[i]); } // 辺集合作成 vector > > neighbors(points.size()); for (int i = 0; i < points.size(); i++) { for (int j = i+1; j < points.size(); j++) { // 塀と角以外の共有点をもったら不可 for (int k = 0; k < hedge.size() - 1; k++) if (abs(points[i] - hedge[k]) >= EPS && abs(points[j] - hedge[k]) >= EPS && abs(points[i] - hedge[k+1]) >= EPS && abs(points[j] - hedge[k+1]) >= EPS && segments_intersect(points[i], points[j], hedge[k], hedge[k+1])) goto invalid; // 塀の角を突き抜けて反対側に出たら不可 for (int k = 1; k < hedge.size() - 1; k++) if (on_segment(hedge[k], points[i], points[j]) && (arg((hedge[k+1] - hedge[k]) / (points[i] - hedge[k])) * arg((hedge[k-1] - hedge[k]) / (points[i] - hedge[k])) < -EPS)) goto invalid; neighbors[i].push_back(make_pair(j, abs(original[i] - original[j]))); neighbors[j].push_back(make_pair(i, abs(original[i] - original[j]))); invalid:; } } return dijkstra(0, 1, neighbors); } int main() { for (int N; cin >> N, N; ) { vector hedge(N); for (int i = 0; i < N; i++) cin >> real(hedge[i]) >> imag(hedge[i]); printf("%.13f\n", solve(hedge)); } return 0; }