#include #include #include #include #include #include #include #include #include #include #include using namespace std; //////////// graph typedef double Weight; struct Edge { int src, dest; Weight weight; Edge() {} Edge(int src, int dest, Weight weight = 0) : src(src), dest(dest), weight(weight) { } friend bool operator<(const Edge& a, const Edge& b) { return (a.weight < b.weight); } friend bool operator>(const Edge& a, const Edge& b) { return (a.weight > b.weight); } }; typedef vector Edges; typedef vector Graph; const Weight WEIGHT_INFTY = numeric_limits::max(); inline void insert_edge(Graph& g, int a, int b, Weight w = 0) { g[a].push_back(Edge(a, b, w)); } enum Const { UNSEEN = -1 , TERMINAL = -2 }; Weight dijkstra(const Graph& g, int start, int goal, vector& trace) { const int n = g.size(); trace.assign(n, UNSEEN); priority_queue, greater > q; q.push(Edge(TERMINAL, start, 0)); while(!q.empty()) { Edge edge = q.top(); q.pop(); if (trace[edge.dest] != UNSEEN) continue; trace[edge.dest] = edge.src; if (edge.dest == goal) return edge.weight; const Edges& edges = g[edge.dest]; for(int i = 0; i < (int)edges.size(); i++) { if (trace[edges[i].dest] == UNSEEN) { q.push(Edge(edge.dest, edges[i].dest, edge.weight + edges[i].weight)); } } } return WEIGHT_INFTY; } ///////////// geom // be aware #define EP 1.0e-10 inline int SGN(double a) { return (abs(a) < EP ? 0 : a > 0 ? 1 : -1); } #define EQ(a,b) (SGN((a)-(b)) == 0) #define NE(a,b) (SGN((a)-(b)) != 0) #define LS(a,b) (SGN((a)-(b)) < 0) #define NG(a) (SGN((a)) < 0) #define NZ(a) (SGN((a)) != 0) typedef complex P; typedef vector

Polygon; inline double inp(const P& a, const P& b) { return (conj(a)*b).real(); } inline double outp(const P& a, const P& b) { return (conj(a)*b).imag(); } inline int ccw(const P& p, const P& r, const P& s) { P a(r-p), b(s-p); double op = outp(a, b); if (SGN(op) != 0) return SGN(op); if (NG(a.real()*b.real()) || NG(a.imag()*b.imag())) return -1; if (LS(norm(a), norm(b))) return 1; return 0; } namespace std { inline bool operator<(const P& a, const P& b) { if (NE(a.real(), b.real())) return LS(a.real(), b.real()); return LS(a.imag(), b.imag()); } } struct polar_less { P pivot; polar_less(const P& pivot) : pivot(pivot) { } bool operator()(const P& a, const P& b) { P z = (a - pivot)/(b - pivot); if (NZ(arg(z))) return (arg(z) < 0); return (abs(z) < 1); } }; struct L { P pos, dir; L() { } L(const P& pos, const P& dir) : pos(pos), dir(dir) { } }; bool ls_intersects(const L& l, const L& s) { return (ccw(l.pos, l.pos+l.dir, s.pos) *ccw(l.pos, l.pos+l.dir, s.pos+s.dir) <= 0); } bool ss_intersects(const L& s, const L& t) { return (ls_intersects(s, t) && ls_intersects(t, s)); } void convex_hull(Polygon& polygon, const Polygon& vertices) { const int n = vertices.size(); assert(n >= 3); polygon = vertices; swap(polygon[0], *min_element(polygon.begin(), polygon.end())); P pivot = polygon[0]; sort(polygon.begin()+1, polygon.end(), polar_less(pivot)); { int tail = n - 1; while(tail > 1 && EQ(arg(polygon[tail-1] - pivot), arg(polygon[n-1] - pivot))) tail--; reverse(polygon.begin()+tail, polygon.end()); } int m = 3; for(int i =3; i < n; i++) { P pt = polygon[i]; while(ccw(polygon[m-2], polygon[m-1], pt) <= 0) m--; polygon[m++] = pt; } polygon.resize(m); } inline P proj(const P& p, const P& b) { return b*inp(p,b)/norm(b); } inline P perf(const L& l, const P& p) { const L m(l.pos - p, l.dir); return (p + (m.pos - proj(m.pos, m.dir))); } inline L proj(const L& s, const L& b) { return L(perf(b, s.pos), proj(s.dir, b.dir)); } struct Q { P pos, actual_pos; }; #define DELTA 1.0e-4 int main() { ifstream fin("hedge.in"); int n; while(fin >> n && n != 0) { Polygon actual_points; for(int i = 0; i < n; i++) { double x, y; fin >> x >> y; actual_points.push_back(P(x, y)); } vector points(2*n); { Q& q1 = points[0]; Q& q2 = points[1]; P dir = actual_points[1] - actual_points[0]; dir = dir / abs(dir) * DELTA; dir *= P(0, 1); q1.pos = actual_points[0] + dir; q2.pos = actual_points[0] - dir; q1.actual_pos = actual_points[0]; q2.actual_pos = actual_points[0]; } { Q& q1 = points[2*n-2]; Q& q2 = points[2*n-1]; P dir = actual_points[n-1] - actual_points[n-2]; dir = dir / abs(dir) * DELTA; dir *= P(0, 1); q1.pos = actual_points[n-1] + dir; q2.pos = actual_points[n-1] - dir; q1.actual_pos = actual_points[n-1]; q2.actual_pos = actual_points[n-1]; } for(int i = 1; i < n-1; i++) { Q& q1 = points[i*2]; Q& q2 = points[i*2+1]; P x, y; x = actual_points[i-1] - actual_points[i]; y = actual_points[i+1] - actual_points[i]; double theta = arg(y/x); theta /= 2; P z1 = x * polar(1.0, theta); z1 = z1 / abs(z1) * DELTA; P z2 = z1 * P(-1, 0); z1 += actual_points[i]; z2 += actual_points[i]; q1.pos = z1; q2.pos = z2; q1.actual_pos = actual_points[i]; q2.actual_pos = actual_points[i]; } int m = 2*n; /* for(int i = 0; i < m; i++) { cout << i << ": " << points[i].pos << endl; } */ Graph g(m); for(int i = 0; i < m; i++) { Q& q1 = points[i]; for(int j = i+1; j < m; j++) { Q& q2 = points[j]; bool intersects = false; for(int z = 0; z < n-1; z++) { if (ss_intersects(L(q1.pos, q2.pos-q1.pos), L(actual_points[z], actual_points[z+1]-actual_points[z]))) { intersects = true; break; } } if (!intersects) { insert_edge(g, i, j, abs(q1.actual_pos-q2.actual_pos)); insert_edge(g, j, i, abs(q1.actual_pos-q2.actual_pos)); //cout << "(" << i << " - " << j << ")" << endl; } } } vector trace; Weight weight = WEIGHT_INFTY; weight = min(weight, dijkstra(g, 0, m-1, trace)); weight = min(weight, dijkstra(g, 1, m-1, trace)); weight = min(weight, dijkstra(g, 0, m-2, trace)); weight = min(weight, dijkstra(g, 1, m-2, trace)); printf("%.10f\n", weight); } return 0; }