Problem:
Problem F:
Tighten Up!
We have a flat panel with two holes.  Pins are nailed on its
surface.  From the back of the panel, a string comes out through one
of the holes to the surface.  The string is then laid on the surface
in a form of a polygonal chain, and goes out to the panel's back through
the other hole.  Initially, the string does not touch any pins.
Figures F-1, F-2, and F-3 show three example layouts of holes, pins and
strings.  In each layout, white squares and circles denote holes and
pins, respectively.  A polygonal chain of solid segments denotes the
string.
Figure F-1: An example layout of holes, pins and a string
Figure F-2: An example layout of holes, pins and a string
Figure F-3: An example layout of holes, pins and a string
When we tie a pair of equal weight stones to the both ends of the
string, the stones slowly straighten the string until there is no
loose part.  The string eventually forms a different polygonal chain as it is
obstructed by some of the pins.  (There are also cases when the
string is obstructed by no pins, though.)
The string does not hook itself while being straightened. A fully
tightened string thus draws a polygonal chain on the surface of the
panel, whose vertices are the positions of some pins with the end
vertices at the two holes. The layouts in Figures F-1, F-2, and F-3 result in the
respective polygonal chains in Figures F-4, F-5, and F-6. Write a program that
calculates the length of the tightened polygonal chain.
Figure F-4: Tightened polygonal chains from the example in Figure F-1.
Figure F-5: Tightened polygonal chains from the example in Figure F-2.
Figure F-6: Tightened polygonal chains from the example in Figure F-3.
Note that the strings, pins and holes are thin enough so that you
can ignore their diameters.
Input
The input consists of multiple datasets, followed by a line containing
two zeros separated by a space.  Each dataset gives the initial shape of the string (i.e., the positions of holes and vertices) and the positions of
pins in the
following format.
m n
x
1
y
1
...
x
l
y
l
The first line has two integers
m
and
n
(2 ≤
m
≤ 100, 0 ≤
n
≤ 100), representing the number of
vertices including two holes that give the initial string shape (
m
) and the number
of pins (
n
).  Each of the following
l
=
m
+
n
lines has two integers
x
i
and
y
i
(0 ≤
x
i
≤ 1000, 0 ≤
y
i
≤ 1000), representing a position
P
i
=
(
x
i
,
y
i
) on the surface of the
panel.
Positions
P
1
, ...,
P
m
give the initial shape of
   the string; i.e., the two holes are at
P
1
and
P
m
, and the string's shape is a polygonal
   chain whose vertices are
P
i
(
i
=
   1, ...,
m
), in this order.
Positions
P
m
+1
, ...,
P
m
+
n
are the positions of
  the pins.
Note that no two points are at the same position.  No three points are
exactly on
a straight line.
Output
For each dataset, the length of the part of the tightened string that
remains on the surface of the panel should be output in a line.
No extra characters
should appear in the
...(truncated)

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;

struct Point {
  double x, y;
  Point operator+(const Point p) const { return {x + p.x, y + p.y}; }
  double operator*(const Point p) const { return x * p.x + y * p.y; }
  Point operator-(const Point p) const { return {x - p.x, y - p.y}; }
  bool operator==(const Point p) const { return x == p.x && y == p.y; }
  Point rot_ccw(const double t) const {
    return {x * cos(t) - y * sin(t), x * sin(t) + y * cos(t)};
  }
  double cross(const Point p) const { return x * p.y - y * p.x; }
  Point scale(const double f) const { return {x * f, y * f}; }
  double dist(const Point p) const { return hypot(x - p.x, y - p.y); }
  double dist2(const Point p) const { return (*this - p) * (*this - p); }
};

struct Segment {
  Point p, q;
  double length() const { return p.dist(q); }
  bool operator==(Segment s) const { return p == s.p && q == s.q; }

  pair<bool, Point> intersect_single_point(const Segment s) const {
    return {intersect(s), intersection_point(s)};
  }

  bool intersect(const Segment& s) const {
    return (orientation(p, q, s.p) * orientation(p, q, s.q) <= 0) &&
           (orientation(s.p, s.q, p) * orientation(s.p, s.q, q) <= 0);
  }

 private:
  Segment scale(const double f) const { return {p, p + (q - p).scale(f)}; }
  short orientation(const Point o, const Point a, const Point b) const {
    const double cross = (a - o).cross(b - o);
    return cross < 0 ? -1 : cross > 0;
  }

  Point intersection_point(const Segment& s) const {
    const double factor = (s.q - s.p).cross(p - s.p) / (q - p).cross(s.q - s.p);
    return scale(factor).q;
  }
};

int N, M;
vector<Point> polyline;
vector<Point> pins;
vector<Segment> path;

vector<vector<double>> memo;

int find_furthest_path_idx(const Segment s, const int from_path_idx) {
  int i = from_path_idx;
  if (!s.intersect(path[i])) return -1;

  double prev_dist = DBL_MIN;

  for (; i < (int)path.size(); i++) {
    const auto [intersects, point] = s.intersect_single_point(path[i]);

    if (intersects && prev_dist <= s.p.dist2(point)) {
      prev_dist = s.p.dist2(point);
    } else {
      break;
    }
  }

  return i;
}

double dp(const int pin_idx, const int path_idx) {
  if (path_idx == -1) return DBL_MAX;
  if (path_idx == (int)path.size()) return pins[pin_idx].dist(polyline.back());
  if (memo[pin_idx][path_idx] > -1) return memo[pin_idx][path_idx];

  double res = DBL_MAX;

  for (int i = 0; i <= M; i++) {
    const Segment movement{pins[pin_idx], pins[i]};
    res = min(res, movement.length() + dp(i, find_furthest_path_idx(movement, path_idx)));
  }

  return memo[pin_idx][path_idx] = res;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  while (cin >> N >> M && N > 0) {
    polyline.resize(N);
    pins.resize(M);
    path.clear();
    for (Point& p : polyline) cin >> p.x >> p.y;
    for (Point& p : pins) cin >> p.x >> p.y;
    for (Point& p : polyline) p = p.rot_ccw(0.00001);
    for (Point& p : pins) p = p.rot_ccw(0.00001);

    for (int i = 0; i < N - 1; i++) {
      const Segment s{polyline[i], polyline[i + 1]};

      vector<pair<double, Segment>> intersections;

      for (const Point pin : pins) {
        const Segment above{pin, {pin.x, 2000}};
        const Segment below{pin, {pin.x, -2000}};
        const auto [intersects_above, point_above] = s.intersect_single_point(above);
        const auto [intersects_below, point_below] = s.intersect_single_point(below);

        if (intersects_above) intersections.emplace_back(s.p.dist2(point_above), above);
        if (intersects_below) intersections.emplace_back(s.p.dist2(point_below), below);
      }

      sort(intersections.begin(), intersections.end(),
           [](const auto a, const auto b) { return a.first < b.first; });

      for (const auto& [_, s] : intersections) {
        if (!path.empty() && path.back() == s) {
          path.pop_back();
        } else {
          path.push_back(s);
        }
      }
    }

    pins.push_back(polyline.back());
    pins.push_back(polyline.front());

    memo.assign(pins.size(), vector<double>(path.size(), -1));

    cout << fixed << setprecision(10) << dp(M + 1, 0) << endl;
  }
}
accuracy: 1
time_ms: 3360
memory_kb: 5296
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;

struct Point {
  double x, y;
  Point operator+(const Point p) const { return {x + p.x, y + p.y}; }
  Point operator-(const Point p) const { return {x - p.x, y - p.y}; }
  bool operator==(const Point p) const { return x == p.x && y == p.y; }
  Point rot_ccw(const double t) const {
    return {x * cos(t) - y * sin(t), x * sin(t) + y * cos(t)};
  }
  double cross(const Point p) const { return x * p.y - y * p.x; }
  Point scale(const double f) const { return {x * f, y * f}; }
  double dist(const Point p) const { return hypot(x - p.x, y - p.y); }
};

struct Segment {
  Point p, q;
  double length() const { return p.dist(q); }
  bool operator==(Segment s) const { return p == s.p && q == s.q; }

  pair<bool, Point> intersect_single_point(const Segment s) const {
    return {intersect(s), intersection_point(s)};
  }

  bool intersect(const Segment& s) const {
    return (orientation(p, q, s.p) * orientation(p, q, s.q) <= 0) &&
           (orientation(s.p, s.q, p) * orientation(s.p, s.q, q) <= 0);
  }

 private:
  Segment scale(const double f) const { return {p, p + (q - p).scale(f)}; }
  short orientation(const Point o, const Point a, const Point b) const {
    const double cross = (a - o).cross(b - o);
    return cross < 0 ? -1 : cross > 0;
  }

  Point intersection_point(const Segment& s) const {
    const double factor = (s.q - s.p).cross(p - s.p) / (q - p).cross(s.q - s.p);
    return scale(factor).q;
  }
};

int N, M;
vector<Point> polyline;
vector<Point> pins;
vector<Segment> path;

vector<vector<double>> memo;

int find_furthest_path_idx(const Segment s, const int from_path_idx) {
  int i = from_path_idx;
  if (!s.intersect(path[i])) return -1;

  double prev_dist = DBL_MIN;

  for (; i < (int)path.size(); i++) {
    const auto [intersects, point] = s.intersect_single_point(path[i]);

    if (intersects && prev_dist <= s.p.dist(point)) {
      prev_dist = s.p.dist(point);
    } else {
      break;
    }
  }

  return i;
}

double dp(const int pin_idx, const int path_idx) {
  if (path_idx == -1) return DBL_MAX;
  if (path_idx == (int)path.size()) return pins[pin_idx].dist(polyline.back());
  if (memo[pin_idx][path_idx] > -1) return memo[pin_idx][path_idx];

  double res = DBL_MAX;

  for (int i = 0; i <= M; i++) {
    const Segment movement{pins[pin_idx], pins[i]};
    res = min(res, movement.length() + dp(i, find_furthest_path_idx(movement, path_idx)));
  }

  return memo[pin_idx][path_idx] = res;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  while (cin >> N >> M && N > 0) {
    polyline.resize(N);
    pins.resize(M);
    path.clear();
    for (Point& p : polyline) cin >> p.x >> p.y;
    for (Point& p : pins) cin >> p.x >> p.y;
    for (Point& p : polyline) p = p.rot_ccw(0.00001);
    for (Point& p : pins) p = p.rot_ccw(0.00001);

    for (int i = 0; i < N - 1; i++) {
      const Segment s{polyline[i], polyline[i + 1]};

      vector<pair<double, Segment>> intersections;

      for (const Point pin : pins) {
        const Segment above{pin, {pin.x, 2000}};
        const Segment below{pin, {pin.x, -2000}};
        const auto [intersects_above, point_above] = s.intersect_single_point(above);
        const auto [intersects_below, point_below] = s.intersect_single_point(below);

        if (intersects_above) intersections.emplace_back(s.p.dist(point_above), above);
        if (intersects_below) intersections.emplace_back(s.p.dist(point_below), below);
      }

      sort(intersections.begin(), intersections.end(),
           [](const auto a, const auto b) { return a.first < b.first; });

      for (const auto& [_, s] : intersections) {
        if (!path.empty() && path.back() == s) {
          path.pop_back();
        } else {
          path.push_back(s);
        }
      }
    }

    pins.push_back(polyline.back());
    pins.push_back(polyline.front());

    memo.assign(pins.size(), vector<double>(path.size(), -1));

    cout << fixed << setprecision(10) << dp(M + 1, 0) << endl;
  }
}
accuracy: 1
time_ms: 5200
memory_kb: 5416
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;

// TODO: Add to index (DP and perhaps geo/misc). Change .at() to []
//       Refactor a bit more, some names are bad.
// TODO: Create folder for Aizu.

struct Point {
  double x, y;
  Point operator+(const Point p) const { return {x + p.x, y + p.y}; }
  Point operator-(const Point p) const { return {x - p.x, y - p.y}; }
  bool operator==(const Point p) const { return x == p.x && y == p.y; }
  Point rot_ccw(const double t) const {
    return {x * cos(t) - y * sin(t), x * sin(t) + y * cos(t)};
  }
  double cross(const Point p) const { return x * p.y - y * p.x; }
  Point scale(const double f) const { return {x * f, y * f}; }
  double dist(const Point p) const { return hypot(x - p.x, y - p.y); }
};

struct Segment {
  Point p, q;
  double length() const { return p.dist(q); }
  bool operator==(Segment s) const { return p == s.p && q == s.q; }

  pair<bool, Point> intersect_single_point(const Segment s) const {
    return {intersect(s), intersection_point(s)};
  }

  bool intersect(const Segment& s) const {
    return (orientation(p, q, s.p) * orientation(p, q, s.q) <= 0) &&
           (orientation(s.p, s.q, p) * orientation(s.p, s.q, q) <= 0);
  }

 private:
  Segment scale(const double f) const { return {p, p + (q - p).scale(f)}; }
  short orientation(const Point o, const Point a, const Point b) const {
    const double cross = (a - o).cross(b - o);
    return cross < 0 ? -1 : cross > 0;
  }

  Point intersection_point(const Segment& s) const {
    const double factor = (s.q - s.p).cross(p - s.p) / (q - p).cross(s.q - s.p);
    return scale(factor).q;
  }
};

int N, M;
vector<Point> polyline;
vector<Point> pins;
vector<Segment> path;

vector<vector<double>> memo;

int find_last_path_idx(const Segment s, const int from_path_idx) {
  int i = from_path_idx;
  if (!s.intersect(path.at(i))) return -1;

  double prev_dist = -1e9;

  for (; i < (int)path.size(); i++) {
    const auto [intersects, point] = s.intersect_single_point(path[i]);

    if (intersects && prev_dist <= s.p.dist(point)) {
      prev_dist = s.p.dist(point);
    } else {
      break;
    }
  }

  return i;
}

double dp(const int pin_idx, const int path_idx) {
  if (path_idx == -1) return 1e8;
  // TODO: This shit is weird. Should be able to return 0 if the previous
  //       "movement" (Segment) was from a pin to the last hole.
  if (path_idx == (int)path.size()) return pins.at(pin_idx).dist(polyline.back());
  if (memo[pin_idx][path_idx] > -1) return memo[pin_idx][path_idx];

  double res = 1e8;

  for (int i = 0; i <= M; i++) {
    const Segment movement{pins.at(pin_idx), pins.at(i)};
    res = min(res, movement.length() + dp(i, find_last_path_idx(movement, path_idx)));
  }

  return memo[pin_idx][path_idx] = res;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  while (cin >> N >> M && N > 0) {
    polyline.resize(N);
    pins.resize(M);
    path.clear();
    for (Point& p : polyline) cin >> p.x >> p.y;
    for (Point& p : pins) cin >> p.x >> p.y;
    for (Point& p : polyline) p = p.rot_ccw(0.00001);
    for (Point& p : pins) p = p.rot_ccw(0.00001);

    for (int i = 0; i < N - 1; i++) {
      const Segment s{polyline[i], polyline[i + 1]};

      vector<pair<double, Segment>> intersections;

      for (const Point pin : pins) {
        const Segment above{pin, {pin.x, 2000}};
        const Segment below{pin, {pin.x, -2000}};
        const auto [intersects_above, point_above] = s.intersect_single_point(above);
        const auto [intersects_below, point_below] = s.intersect_single_point(below);

        if (intersects_above) intersections.emplace_back(s.p.dist(point_above), above);
        if (intersects_below) intersections.emplace_back(s.p.dist(point_below), below);
      }

      sort(intersections.begin(), intersections.end(),
           [](const auto a, const auto b) { return a.first < b.first; });

      for (const auto& [_, s] : intersections) {
        if (!path.empty() && path.back() == s) {
          path.pop_back();
        } else {
          path.push_back(s);
        }
      }
    }

    pins.push_back(polyline.back());
    pins.push_back(polyline.front());

    memo.assign(pins.size(), vector<double>(path.size(), -1));

    cout << fixed << setprecision(10) << dp(M + 1, 0) << endl;
  }
}
accuracy: 1
time_ms: 5280
memory_kb: 5472
final_rank: 15

code_snippet: #include <bits/stdc++.h>
using namespace std;

// TODO: Add to index (DP and perhaps geo/misc). Change .at() to []
//       Refactor a bit more, some names are bad.
// TODO: Create folder for Aizu.

struct Point {
  double x, y;
  Point operator+(const Point p) const { return {x + p.x, y + p.y}; }
  Point operator-(const Point p) const { return {x - p.x, y - p.y}; }
  bool operator==(const Point p) const { return x == p.x && y == p.y; }
  Point rot_ccw(const double t) const {
    return {x * cos(t) - y * sin(t), x * sin(t) + y * cos(t)};
  }
  double cross(const Point p) const { return x * p.y - y * p.x; }
  Point scale(const double f) const { return {x * f, y * f}; }
  double dist(const Point p) const { return hypot(x - p.x, y - p.y); }
};

struct Segment {
  Point p, q;
  Segment scale(const double f) const { return {p, p + (q - p).scale(f)}; }
  double length() const { return p.dist(q); }
  bool operator==(Segment s) const { return p == s.p && q == s.q; }

  pair<bool, Point> intersect_single_point(const Segment s) const {
    return intersect(s) ? make_pair(true, intersection_point(s))
                        : make_pair(false, Point{});
  }

  bool intersect(const Segment& s) const {
    return (orientation(p, q, s.p) * orientation(p, q, s.q) <= 0) &&
           (orientation(s.p, s.q, p) * orientation(s.p, s.q, q) <= 0);
  }

 private:
  short orientation(const Point o, const Point a, const Point b) const {
    const double cross = (a - o).cross(b - o);
    return cross < 0 ? -1 : cross > 0;
  }

  Point intersection_point(const Segment& s) const {
    const double factor = (s.q - s.p).cross(p - s.p) / (q - p).cross(s.q - s.p);
    return scale(factor).q;
  }
};

int N, M;
vector<Point> polyline;
vector<Point> pins;
vector<Segment> path;

vector<vector<double>> memo;

int find_last_path_idx(const Segment s, const int from_path_idx) {
  int i = from_path_idx;
  if (!s.intersect(path.at(i))) return -1;

  double prev_dist = -1e9;

  for (; i < (int)path.size(); i++) {
    const auto [intersects, point] = s.intersect_single_point(path[i]);

    if (intersects && prev_dist <= s.p.dist(point)) {
      prev_dist = s.p.dist(point);
    } else {
      break;
    }
  }

  return i;
}

double dp(const int curr_idx, const int path_idx) {
  if (path_idx == -1) return 1e8;
  // TODO: This shit is weird. Should be able to return 0 if the previous
  //       "movement" (Segment) was from a pin to the last hole.
  if (path_idx == (int)path.size()) return pins.at(curr_idx).dist(polyline.back());
  if (memo[curr_idx][path_idx] > -1) return memo[curr_idx][path_idx];

  double res = 1e8;

  for (int i = 0; i <= M; i++) {
    const Segment movement{pins.at(curr_idx), pins.at(i)};
    res = min(res, movement.length() + dp(i, find_last_path_idx(movement, path_idx)));
  }

  return memo[curr_idx][path_idx] = res;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  while (cin >> N >> M && N > 0) {
    polyline.resize(N);
    pins.resize(M);
    for (Point& p : polyline) cin >> p.x >> p.y;
    for (Point& p : pins) cin >> p.x >> p.y;
    for (Point& p : polyline) p = p.rot_ccw(0.00001);
    for (Point& p : pins) p = p.rot_ccw(0.00001);

    vector<Segment> segments;
    path.clear();

    for (Point p : pins) {
      segments.push_back({p, {p.x, 2000}});
      segments.push_back({p, {p.x, -2000}});
    }

    for (int i = 0; i < N - 1; i++) {
      const Segment s{polyline[i], polyline[i + 1]};

      vector<pair<double, Segment>> intersections;

      for (const Segment r : segments) {
        const auto [intersects, point] = s.intersect_single_point(r);

        if (!intersects) continue;
        intersections.emplace_back(s.p.dist(point), r);
      }

      sort(intersections.begin(), intersections.end(),
           [](const auto a, const auto b) { return a.first < b.first; });

      for (const auto& [_, seg] : intersections) {
        if (!path.empty() && path.back() == seg) {
          path.pop_back();
        } else {
          path.push_back(seg);
        }
      }
    }

    pins.push_back(polyline.back());
    pins.push_back(polyline.front());

    memo.assign(pins.size(), vector<double>(path.size(), -1));

    cout << fixed << setprecision(10) << dp(M + 1, 0) << endl;
  }
}
accuracy: 1
time_ms: 5170
memory_kb: 5324
final_rank: 13

code_snippet: #include <bits/stdc++.h>
using namespace std;

// TODO: Add to index (DP and perhaps geo/misc). Change .at() to []
//       Refactor a bit more, some names are bad.
// TODO: Create folder for Aizu.

struct Point {
  double x, y;
  Point operator+(const Point p) const { return {x + p.x, y + p.y}; }
  Point operator-(const Point p) const { return {x - p.x, y - p.y}; }
  bool operator==(const Point p) const { return x == p.x && y == p.y; }
  Point rot_ccw(const double t) const {
    return {x * cos(t) - y * sin(t), x * sin(t) + y * cos(t)};
  }
  double cross(const Point p) const { return x * p.y - y * p.x; }
  Point scale(const double f) const { return {x * f, y * f}; }
  double dist(const Point p) const { return hypot(x - p.x, y - p.y); }
};

struct Segment {
  Point p, q;
  Segment scale(const double f) const { return {p, p + (q - p).scale(f)}; }
  double length() const { return p.dist(q); }
  bool operator==(Segment s) const { return p == s.p && q == s.q; }

  pair<bool, Point> intersect_single_point(const Segment s) const {
    return intersect(s) ? make_pair(true, intersection_point(s))
                        : make_pair(false, Point{});
  }

  bool intersect(const Segment& s) const {
    return (orientation(p, q, s.p) * orientation(p, q, s.q) <= 0) &&
           (orientation(s.p, s.q, p) * orientation(s.p, s.q, q) <= 0);
  }

 private:
  short orientation(const Point o, const Point a, const Point b) const {
    const double cross = (a - o).cross(b - o);
    return cross < 0 ? -1 : cross > 0;
  }

  Point intersection_point(const Segment& s) const {
    const double factor = (s.q - s.p).cross(p - s.p) / (q - p).cross(s.q - s.p);
    return scale(factor).q;
  }
};

int N, M;
vector<Point> polyline;
vector<Point> pins;
vector<Segment> path;

// double memo[107][10007];
// bool ok[107][10007];
unordered_map<int, double> memo;

int find_last_path_idx(const Segment s, const int from_path_idx) {
  int i = from_path_idx;
  if (!s.intersect(path.at(i))) return -1;

  double prev_dist = -1e9;

  for (; i < (int)path.size(); i++) {
    const auto [intersects, point] = s.intersect_single_point(path[i]);

    if (intersects && prev_dist <= s.p.dist(point)) {
      prev_dist = s.p.dist(point);
    } else {
      break;
    }
  }

  return i;
}

double dp(const int curr_idx, const int path_idx) {
  if (path_idx == -1) return 1e8;
  // TODO: This shit is weird. Should be able to return 0 if the previous
  //       "movement" (Segment) was from a pin to the last hole.
  if (path_idx == (int)path.size()) return pins.at(curr_idx).dist(polyline.back());
  if (memo.count(curr_idx + 10000 * path_idx)) return memo[curr_idx + 10000 * path_idx];

  double res = 1e8;

  for (int i = 0; i <= M; i++) {
    const Segment movement{pins.at(curr_idx), pins.at(i)};
    res = min(res, movement.length() + dp(i, find_last_path_idx(movement, path_idx)));
  }

  return memo[curr_idx + 10000 * path_idx] = res;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  while (cin >> N >> M && N > 0) {
    // memset(ok, 0, sizeof ok);
    memo.clear();
    polyline.resize(N);
    pins.resize(M);
    for (Point& p : polyline) cin >> p.x >> p.y;
    for (Point& p : pins) cin >> p.x >> p.y;
    for (Point& p : polyline) p = p.rot_ccw(0.00001);
    for (Point& p : pins) p = p.rot_ccw(0.00001);

    vector<Segment> segments;
    path.clear();

    for (Point p : pins) {
      segments.push_back({p, {p.x, 2000}});
      segments.push_back({p, {p.x, -2000}});
    }

    for (int i = 0; i < N - 1; i++) {
      const Segment s{polyline[i], polyline[i + 1]};

      vector<pair<double, Segment>> intersections;

      for (const Segment r : segments) {
        const auto [intersects, point] = s.intersect_single_point(r);

        if (!intersects) continue;
        intersections.emplace_back(s.p.dist(point), r);
      }

      sort(intersections.begin(), intersections.end(),
           [](const auto a, const auto b) { return a.first < b.first; });

      for (const auto& [_, seg] : intersections) {
        if (!path.empty() && path.back() == seg) {
          path.pop_back();
        } else {
          path.push_back(seg);
        }
      }
    }

    pins.push_back(polyline.back());
    pins.push_back(polyline.front());

    cout << fixed << setprecision(10) << dp(M + 1, 0) << endl;
  }
}
accuracy: 1
time_ms: 5840
memory_kb: 9480
final_rank: 20

code_snippet: #include <bits/stdc++.h>
using namespace std;

// TODO: Add to index (DP and perhaps geo/misc). Change .at() to []
//       Refactor a bit more, some names are bad.
// TODO: Create folder for Aizu.

struct Point {
  double x, y;
  Point operator+(const Point p) const { return {x + p.x, y + p.y}; }
  Point operator-(const Point p) const { return {x - p.x, y - p.y}; }
  bool operator==(const Point p) const { return x == p.x && y == p.y; }
  Point rot_ccw(const double t) const {
    return {x * cos(t) - y * sin(t), x * sin(t) + y * cos(t)};
  }
  double cross(const Point p) const { return x * p.y - y * p.x; }
  Point scale(const double f) const { return {x * f, y * f}; }
  double dist(const Point p) const { return hypot(x - p.x, y - p.y); }
};

struct Segment {
  Point p, q;
  Segment scale(const double f) const { return {p, p + (q - p).scale(f)}; }
  double length() const { return p.dist(q); }
  bool operator==(Segment s) const { return p == s.p && q == s.q; }

  pair<bool, Point> intersect_single_point(const Segment s) const {
    return intersect(s) ? make_pair(true, intersection_point(s))
                        : make_pair(false, Point{});
  }

  bool intersect(const Segment& s) const {
    return (orientation(p, q, s.p) * orientation(p, q, s.q) <= 0) &&
           (orientation(s.p, s.q, p) * orientation(s.p, s.q, q) <= 0);
  }

 private:
  short orientation(const Point o, const Point a, const Point b) const {
    const double cross = (a - o).cross(b - o);
    return cross < 0 ? -1 : cross > 0;
  }

  Point intersection_point(const Segment& s) const {
    const double factor = (s.q - s.p).cross(p - s.p) / (q - p).cross(s.q - s.p);
    return scale(factor).q;
  }
};

int N, M;
vector<Point> polyline;
vector<Point> pins;
vector<Segment> path;

double memo[107][10007];
bool ok[107][10007];

int find_last_path_idx(const Segment s, const int from_path_idx) {
  int i = from_path_idx;
  if (!s.intersect(path.at(i))) return -1;

  double prev_dist = -1e9;

  for (; i < (int)path.size(); i++) {
    const auto [intersects, point] = s.intersect_single_point(path[i]);

    if (intersects && prev_dist <= s.p.dist(point)) {
      prev_dist = s.p.dist(point);
    } else {
      break;
    }
  }

  return i;
}

double dp(const int curr_idx, const int path_idx) {
  if (path_idx == -1) return 1e8;
  // TODO: This shit is weird. Should be able to return 0 if the previous
  //       "movement" (Segment) was from a pin to the last hole.
  if (path_idx == (int)path.size()) return pins.at(curr_idx).dist(polyline.back());
  if (ok[curr_idx][path_idx]) return memo[curr_idx][path_idx];

  double res = 1e8;

  for (int i = 0; i <= M; i++) {
    const Segment movement{pins.at(curr_idx), pins.at(i)};
    res = min(res, movement.length() + dp(i, find_last_path_idx(movement, path_idx)));
  }

  ok[curr_idx][path_idx] = true;
  return memo[curr_idx][path_idx] = res;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  while (cin >> N >> M && N > 0) {
    memset(ok, 0, sizeof ok);
    polyline.resize(N);
    pins.resize(M);
    for (Point& p : polyline) cin >> p.x >> p.y;
    for (Point& p : pins) cin >> p.x >> p.y;
    for (Point& p : polyline) p = p.rot_ccw(0.00001);
    for (Point& p : pins) p = p.rot_ccw(0.00001);

    vector<Segment> segments;
    path.clear();

    for (Point p : pins) {
      segments.push_back({p, {p.x, 2000}});
      segments.push_back({p, {p.x, -2000}});
    }

    for (int i = 0; i < N - 1; i++) {
      const Segment s{polyline[i], polyline[i + 1]};

      vector<pair<double, Segment>> intersections;

      for (const Segment r : segments) {
        const auto [intersects, point] = s.intersect_single_point(r);

        if (!intersects) continue;
        intersections.emplace_back(s.p.dist(point), r);
      }

      sort(intersections.begin(), intersections.end(),
           [](const auto a, const auto b) { return a.first < b.first; });

      for (const auto& [_, seg] : intersections) {
        if (!path.empty() && path.back() == seg) {
          path.pop_back();
        } else {
          path.push_back(seg);
        }
      }
    }

    pins.push_back(polyline.back());
    pins.push_back(polyline.front());

    cout << fixed << setprecision(10) << dp(M + 1, 0) << endl;
  }
}
accuracy: 1
time_ms: 5180
memory_kb: 11400
final_rank: 17

code_snippet: #include <bits/stdc++.h>
using namespace std;

struct Point {
  double x, y;
  Point operator+(const Point p) const { return {x + p.x, y + p.y}; }
  Point operator-(const Point p) const { return {x - p.x, y - p.y}; }
  bool operator==(const Point p) const { return x == p.x && y == p.y; }
  Point rot_ccw(const double t) const {
    return {x * cos(t) - y * sin(t), x * sin(t) + y * cos(t)};
  }
  double cross(const Point p) const { return x * p.y - y * p.x; }
  Point scale(const double f) const { return {x * f, y * f}; }
  double dist(const Point p) const { return hypot(x - p.x, y - p.y); }
};

struct Segment {
  Point p, q;
  Segment scale(const double f) const { return {p, p + (q - p).scale(f)}; }
  double length() const { return p.dist(q); }
  bool operator==(Segment s) const { return p == s.p && q == s.q; }

  pair<bool, Point> intersect_single_point(const Segment s) const {
    return intersect(s) ? make_pair(true, intersection_point(s))
                        : make_pair(false, Point{});
  }

  bool intersect(const Segment& s) const {
    return (orientation(p, q, s.p) * orientation(p, q, s.q) <= 0) &&
           (orientation(s.p, s.q, p) * orientation(s.p, s.q, q) <= 0);
  }

 private:
  short orientation(const Point o, const Point a, const Point b) const {
    const double cross = (a - o).cross(b - o);
    return cross < 0 ? -1 : cross > 0;
  }

  Point intersection_point(const Segment& s) const {
    const double factor = (s.q - s.p).cross(p - s.p) / (q - p).cross(s.q - s.p);
    return scale(factor).q;
  }
};

int N, M;
vector<Point> polyline;
vector<Point> pins;
vector<Segment> path;

// TODO: This shouldn't crash if it's 101 (size of first dimension)
double memo[107][10007];
bool ok[107][10007];

int find_last_path_idx(const Segment s, const int from_path_idx) {
  int i = from_path_idx;
  if (!s.intersect(path.at(i))) return -1;

  double prev_dist = -1e9;

  for (; i < (int)path.size(); i++) {
    const auto [intersects, point] = s.intersect_single_point(path[i]);

    if (intersects && prev_dist <= s.p.dist(point)) {
      prev_dist = s.p.dist(point);
    } else {
      break;
    }
  }

  return i;
}

double dp(const int curr_idx, const int path_idx) {
  if (path_idx == -1) return 1e8;
  // TODO: This shit is weird. Should be able to return 0 if the previous
  //       "movement" (Segment) was from a pin to the last hole.
  if (path_idx == (int)path.size()) return pins.at(curr_idx).dist(polyline.back());
  if (ok[curr_idx][path_idx]) return memo[curr_idx][path_idx];

  double res = 1e8;

  for (int i = 0; i <= M; i++) {
    const Segment movement{pins.at(curr_idx), pins.at(i)};
    res = min(res, movement.length() + dp(i, find_last_path_idx(movement, path_idx)));
  }

  ok[curr_idx][path_idx] = true;
  return memo[curr_idx][path_idx] = res;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  while (cin >> N >> M && N > 0) {
    memset(ok, 0, sizeof ok);
    polyline.resize(N);
    pins.resize(M);
    for (Point& p : polyline) cin >> p.x >> p.y;
    for (Point& p : pins) cin >> p.x >> p.y;
    for (Point& p : polyline) p = p.rot_ccw(0.00001);
    for (Point& p : pins) p = p.rot_ccw(0.00001);

    vector<Segment> segments;
    path.clear();

    for (Point p : pins) {
      segments.push_back({p, {p.x, 2000}});
      segments.push_back({p, {p.x, -2000}});
    }

    for (int i = 0; i < N - 1; i++) {
      const Segment s{polyline[i], polyline[i + 1]};

      vector<pair<double, Segment>> intersections;

      for (const Segment r : segments) {
        const auto [intersects, point] = s.intersect_single_point(r);

        if (!intersects) continue;
        intersections.emplace_back(s.p.dist(point), r);
      }
 
      sort(intersections.begin(), intersections.end(),
           [](const auto a, const auto b) { return a.first < b.first; });

      for (const auto& [_, seg] : intersections) {
        if (!path.empty() && path.back() == seg) {
          path.pop_back();
        } else {
          path.push_back(seg);
        }
      }
    }

    pins.push_back(polyline.back());
    pins.push_back(polyline.front());

    cout << fixed << setprecision(10) << dp(M + 1, 0) << endl;
  }
}
accuracy: 1
time_ms: 5190
memory_kb: 11404
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef double ld;
  
const ld EPS = 1e-7;

inline bool zero(const ld x) { return fabs(x) < EPS; }
inline bool equal(const ld a, const ld b) { return zero(a - b); }

struct Point {
  ld x, y;
  Point operator+(const Point p) const { return {x + p.x, y + p.y}; }
  Point operator-(const Point p) const { return {x - p.x, y - p.y}; }
  bool operator==(const Point p) const { return x == p.x && y == p.y; }
  // bool operator==(const Point p) const { return equal(x, p.x) && equal(y, p.y); }
  Point rot_ccw(const ld t) const {
    return {x * cos(t) - y * sin(t), x * sin(t) + y * cos(t)};
  }
  ld cross(const Point p) const { return x * p.y - y * p.x; }
  ld operator*(const Point p) const { return x * p.x + y * p.y; }
  Point scale(const ld f) const { return {x * f, y * f}; }
  ld dist(const Point p) const { return hypot(x - p.x, y - p.y); }
  // bool operator<(const Point p) const { return make_pair(x, y) < make_pair(p.x, p.y); }
};

short orientation(const Point o, const Point a, const Point b) {
  const ld cross = (a - o).cross(b - o);
  if (zero(cross)) return 0;
  return cross < 0 ? -1 : cross > 0;
}

ostream& operator<<(ostream& os, const Point& p) {
  return os << fixed << setprecision(6) << "(" << p.x << ", " << p.y << ")";
}

struct Segment {
  Point p, q;
  string to_desmos() const {
    stringstream ss;
    ss << fixed << setprecision(6) << "\\left(\\left(1-t\\right)\\cdot" << p.x
       << "+t\\cdot" << q.x << ",\\left(1-t\\right)\\cdot" << p.y << "+t\\cdot" << q.y
       << "\\right)";
    return ss.str();
  }
  Segment scale(const ld f) const { return {p, p + (q - p).scale(f)}; }
  ld length() const { return p.dist(q); }
  bool operator==(Segment s) const { return p == s.p && q == s.q; }

  // TODO: This is no longer "non-collinear". Rename/refactor.
  pair<bool, Point> intersect_non_collinear(const Segment s) const {
    return intersect(s) ? make_pair(true, intersection_point(s))
                        : make_pair(false, Point{});
  }

  bool intersect(const Segment& s) const {
    if (p == s.p) return true;
    if (p == s.q) return true;
    if (q == s.p) return true;
    if (q == s.q) return true;
    return (orientation(p, q, s.p) * orientation(p, q, s.q) <= 0) &&
           (orientation(s.p, s.q, p) * orientation(s.p, s.q, q) <= 0);
  }

 private:
  Point intersection_point(const Segment& s) const {
    const ld factor = (s.q - s.p).cross(p - s.p) / (q - p).cross(s.q - s.p);
    return scale(factor).q;
  }
};

int N, M;
vector<Point> polyline;
vector<Point> pins;
vector<Segment> path;

// TODO: This shouldn't crash if it's 101 (size of first dimension)
ld memo[131][2500];
bool ok[131][2500];

int find_last_path_idx(const Segment s, const int from_path_idx) {
  int i = from_path_idx;
  if (!s.intersect(path.at(i))) return -1;

  ld prev_dist = -1e9;

  for (; i < (int)path.size(); i++) {
    const auto [intersects, point] = s.intersect_non_collinear(path[i]);
    if (!intersects) break;

    if (prev_dist <= s.p.dist(point)) {
      prev_dist = s.p.dist(point);
    } else {
      break;
    }
  }

  assert(i <= (int)path.size());

  return i;
}

ld dp(const int curr_idx, const int path_idx) {
  assert(curr_idx >= 0 && curr_idx <= M + 1);

  if (path_idx == -1) return 1e8;
  // if (curr_idx == M) return 0;

  assert(path_idx >= 0 && path_idx <= (int)path.size() * 2);

  if (path_idx == (int)path.size()) {
    // TODO: This shit is weird. Should be able to return 0 if the previous
    //       "movement" (Segment) was from a pin to the last hole.
    return pins.at(curr_idx).dist(polyline.back());
  }

  if (ok[curr_idx][path_idx]) return memo[curr_idx][path_idx];

  ld res = 1e8;

  for (int i = 0; i <= M; i++) {
    // TODO: Maybe something is weird here... but if I remove this check, then the
    //       segment will become a p==q segment and the find_last_path_idx will misbehave.
    if (i == curr_idx) continue;

    const Segment movement{pins.at(curr_idx), pins.at(i)};
    res = min(res, movement.length() + dp(i, find_last_path_idx(movement, path_idx)));
  }

  ok[curr_idx][path_idx] = true;
  return memo[curr_idx][path_idx] = res;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);

  while (cin >> N >> M && N > 0) {
    memset(ok, 0, sizeof ok);
    polyline.resize(N);
    pins.resize(M);
    for (Point& p : polyline) cin >> p.x >> p.y;
    for (Point& p : pins) cin >> p.x >> p.y;
    for (Point& p : polyline) p = p.rot_ccw(0.00001);
    for (Point& p : pins) p = p.rot_ccw(0.00001);

    assert(M < 101);
    assert(N < 101);

    if (true) {
      sort(pins.begin(), pins.end(), [](auto a, auto b) { return a.x < b.x; });

      vector<ld> all_x;
      for (Point& p : polyline) all_x.emplace_back(p.x);
      for (Point& p : pins) all_x.emplace_back(p.x);
      sort(all_x.begin(), all_x.end());

      for (int i = 0; i < (int)all_x.size() - 1; i++) {
        assert(all_x[i] < all_x[i + 1]);
        assert(!equal(all_x[i], all_x[i + 1]));
      }
    }

    vector<Segment> segments;
    path.clear();

    for (Point p : pins) {
      segments.push_back({p, {p.x, 10'000}});
      segments.push_back({p, {p.x, -10'000}});
    }

    for (int i = 0; i < N - 1; i++) {
      const Segment s{polyline[i], polyline[i + 1]};

      for (Point pin : pins) {
        assert(orientation(s.p, s.q, pin) != 0);
      }
    }

    for (int i = 0; i < N - 1; i++) {
      const Segment s{polyline[i], polyline[i + 1]};

      vector<pair<ld, Segment>> intersections;

      for (const Segment r : segments) {
        const auto [intersects, point] = s.intersect_non_collinear(r);

        if (!intersects) continue;
        intersections.emplace_back(s.p.dist(point), r);
      }

      sort(intersections.begin(), intersections.end(),
           [](const auto a, const auto b) { return a.first < b.first; });

      for (int j = 0; j < (int)intersections.size(); j++) {
        for (int k = j + 1; k < (int)intersections.size(); k++) {
          assert(!equal(intersections[j].second.p.x, intersections[k].second.p.x));
          assert(!equal(intersections[j].second.q.x, intersections[k].second.q.x));
        }
      }

      for (const auto& [_, seg] : intersections) {
        if (!path.empty() && path.back() == seg) {
          path.pop_back();
        } else {
          path.push_back(seg);
        }
      }
    }

    pins.push_back(polyline.back());
    pins.push_back(polyline.front());

    if (false && N == 100 && M == 100) {
      for (int i = 0; i < N - 1; i++) {
        const Segment s{polyline[i], polyline[i + 1]};
        cerr << s.to_desmos() << endl;
      }
      for (Point pin : pins) {
        cerr << pin << endl;
      }
      cerr << fixed << setprecision(10) << dp(M + 1, 0) << endl;
      for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
          if (equal(polyline[i].dist(polyline[j]), dp(M + 1, 0))) {
            cerr << "HAHAHAHAHAH" << endl;
          }
        }
      }
      assert(false);
    }

    cout << fixed << setprecision(10) << dp(M + 1, 0) << endl;
  }
}
accuracy: 1
time_ms: 5580
memory_kb: 6096
final_rank: 16

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long double ld; 
const ld eps=1E-15;
const ld pi=acos(-1);
const ld INF=1E15;
const int maxn=1E6+5; 
int q,n,m,top;
ld ans,f[maxn];
bool vis[maxn];
int size,head[maxn];
struct pt
{
	ld x,y;
	pt(ld a=0,ld b=0)
	{
		x=a,y=b;
	}
	void operator=(pt A)
	{
		x=A.x,y=A.y;
	}
	ld operator*(pt A)
	{
		return x*A.y-y*A.x;
	}
	pt operator-(pt A)
	{
		return pt(x-A.x,y-A.y);
	}
}target[maxn],barrier[maxn];
struct inf
{
	int id,x;
	inf(int a=0,int b=0)
	{
		id=a,x=b;
	}
}S[maxn];
struct edge
{
	int to,next;
	ld w;
}E[maxn];
//////////////////////////////////////////////////////////////////
//polygon
//////////////////////////////////////////////////////////////////
bool cmp(pt A,pt B)
{
	return A.x<B.x;
}
pt rotate(pt A,ld ra)
{
	return pt(A.x*cos(ra)-A.y*sin(ra),A.x*sin(ra)+A.y*cos(ra));
}
int face(pt A,pt B,pt C)
{
	ld y=(B.y-A.y)/(B.x-A.x)*(C.x-A.x);
	if(A.y+y>=C.y)
		return 1;
	return -1;
}
bool inside(pt A,pt B,pt C)
{
	return min(A.x,B.x)<=C.x&&C.x<=max(A.x,B.x);
}
ld dis(pt A,pt B)
{
	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}
int cross(pt A,pt B)
{
	ld d=A*B;
	if(d>=eps)
		return 1;
	else
		return -1;
}
void push(inf A)
{
	if(A.id==S[top].id&&A.x==S[top].x)
		--top;
	else
		S[++top]=A;
}
//////////////////////////////////////////////////////////////////
//polygon
//////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////
//graph
//////////////////////////////////////////////////////////////////
void add(int u,int v,ld w)
{
	E[++size].to=v;
	E[size].next=head[u];
	E[size].w=w;
	head[u]=size;
}
void clear()
{
	for(int i=0;i<=top+1;++i)
		head[i]=0;
	head[maxn-5]=0;
	size=0;
}
ld spfa()
{
	for(int i=0;i<=top;++i)
		f[i]=INF;
	f[0]=0;
	vis[0]=1;
	queue<int>Q;
	Q.push(0);
	while(!Q.empty())
	{
		int u=Q.front();
		vis[u]=0;
		Q.pop();
		for(int i=head[u];i;i=E[i].next)
		{
			int v=E[i].to;
			ld nw=E[i].w+f[u];
			if(nw<f[v])
			{
				f[v]=nw;
				if(!vis[v])
				{
					vis[v]=1;
					Q.push(v);
				}
			}
		}
	}
	return f[top--];
}
bool check(int l,int r)
{
	for(int i=l+1;i<=r-1;++i)
		if(face(barrier[S[l].id],barrier[S[r].id],barrier[S[i].id])!=S[i].x)
			return false;
	return true;
} 
ld get(int x)
{
	clear();
	barrier[maxn-5]=target[x];
	push(inf(maxn-5,0));
	for(int i=1;i<=top;++i)
		for(int j=i+1;j<=top;++j)
			if(check(i,j))
				add(i,j,dis(barrier[S[i].id],barrier[S[j].id]));
	barrier[0]=target[1];
	for(int i=1;i<=top;++i)
		if(check(0,i))
			add(0,i,dis(barrier[0],barrier[S[i].id]));
	return spfa();
}

//////////////////////////////////////////////////////////////////
//graph
//////////////////////////////////////////////////////////////////

void solve()
{
	top=ans=0;
	cin>>n>>m;
	if(n==0&&m==0)
		exit(0);
	for(int i=1;i<=n;++i)
	{
		cin>>target[i].x>>target[i].y;
		target[i]=rotate(target[i],pi/3);
	}
	for(int i=1;i<=m;++i)
	{
		cin>>barrier[i].x>>barrier[i].y;
		barrier[i]=rotate(barrier[i],pi/3);
	}
	sort(barrier+1,barrier+m+1,cmp);
	pt now=target[1];
	for(int i=2;i<=n;++i)
	{
		if(target[i].x>now.x)
		{
			for(int j=1;j<=m;++j)
				if(inside(now,target[i],barrier[j]))
					push(inf(j,face(now,target[i],barrier[j])));
		}
		else
		{
			for(int j=m;j>=1;--j)
				if(inside(now,target[i],barrier[j]))
					push(inf(j,face(now,target[i],barrier[j])));
		}
		now=target[i];
	}
	cout<<fixed<<setprecision(4)<<get(n)<<endl;
}
int main()
{
	ios::sync_with_stdio(false);
	while(true)
		solve();
	return 0;
}
accuracy: 1
time_ms: 530
memory_kb: 74300
final_rank: 19

code_snippet: #include <iostream>
#include <iomanip>
#include <complex>
#include <vector>
#include <algorithm>
#include <cmath>
#include <array>
using namespace std;
const double EPS = 1e-10;
const double INF = 1e12;
const double PI = acos(-1);
#define EQ(n,m) (abs((n)-(m)) < EPS)
#define X real()
#define Y imag()
typedef complex<double> P;
typedef vector<P> VP;
struct L : array<P, 2>{
    L(const P& a, const P& b){ at(0)=a; at(1)=b; }
    L(){}
};

namespace std{
    bool operator < (const P& a, const P& b){
        return !EQ(a.X,b.X) ? a.X<b.X : a.Y+EPS<b.Y;
    }
    bool operator == (const P& a, const P& b){
        return abs(a-b) < EPS;
    }
}

double dot(P a, P b){
    return (conj(a)*b).X;
}
double cross(P a, P b){
    return (conj(a)*b).Y;
}
int ccw(P a, P b, P c){
    b -= a;
    c -= a;
    if(cross(b,c) > EPS) return +1; //ccw
    if(cross(b,c) < -EPS) return -1; //cw
    if(dot(b,c) < -EPS) return +2; //c-a-b
    if(abs(c)-abs(b) > EPS) return -2; //a-b-c
    return 0; //a-c-b
}

bool intersectSS(const L& a, const L& b){
    return ( ccw(a[0],a[1],b[0]) *ccw(a[0],a[1],b[1]) <= 0 ) &&
        ( ccw(b[0],b[1],a[0]) *ccw(b[0],b[1],a[1]) <= 0 );
}

double shortest_path(P begin, P end, vector<L> &pl){
    pl.insert(pl.begin(), L(begin, begin));
    pl.push_back(L(end, end));
    int n = pl.size();
    vector<vector<double> > dp(n, vector<double>(2, INF));
    dp[0][0] = 0;
    for(int i=0; i<n; i++){
        for(int j=i+1; j<n; j++){
            for(int s=0; s<2; s++){
                for(int t=0; t<2; t++){
                    L edge(pl[i][s], pl[j][t]);
                    bool ok = true;
                    for(int k=i+1; k<j; k++){
                        if(!intersectSS(edge, pl[k])){
                            ok = false;
                            break;
                        }
                    }
                    if(ok){
                        dp[j][t] = min(dp[j][t], dp[i][s] +abs(edge[1] -edge[0]));
                    }
                }
            }
        }
    }
    return dp[n-1][0];
}

int main(){
    while(1){
        int m,n;
        cin >> m >> n;
        if(m == 0) break;

        VP p(m), pin(n);
        P rot(cos(0.01), sin(0.01));
        for(int i=0; i<m; i++){
            double x,y;
            cin >> x >> y;
            p[i] = P(x, y)*rot;
        }
        for(int i=0; i<n; i++){
            double x,y;
            cin >> x >> y;
            pin[i] = P(x, y)*rot;
        }

        sort(pin.begin(), pin.end());
        vector<L> ls;
        for(int i=0; i<n; i++){
            ls.emplace_back(P(pin[i].X, -1e4), pin[i]);
            ls.emplace_back(pin[i], P(pin[i].X, 1e4));
        }

        vector<int> pass;
        for(int i=0; i<m-1; i++){
            L line(p[i], p[i+1]);
            if(EQ(line[0].X, line[1].X)) continue;
            bool goR = line[0].X < line[1].X;
            int j = goR? 0: ls.size()-1;
            while((goR && j<(int)ls.size()) || (!goR && j>=0)){
                if(intersectSS(ls[j], line)){
                    if(pass.empty() || pass.back() != j){
                        pass.push_back(j);
                    }else{
                        pass.pop_back();
                    }
                }
                if(goR) j++;
                else j--;
            }
        }

        double ans = 0;
        P start = p[0];
        vector<L> pl;
        for(int i=0; i<(int)pass.size(); i++){
            if(i!=(int)pass.size()-1 && EQ(ls[pass[i]][0].X, ls[pass[i+1]][0].X)){
                P end;
                if(ls[pass[i]][0].Y < ls[pass[i+1]][0].Y){
                    end = ls[pass[i]][1];
                }else{
                    end = ls[pass[i]][0];
                }
                ans += shortest_path(start, end, pl);
                start = end;
                pl = vector<L>();
            }else{
                pl.push_back(ls[pass[i]]);
            }
            if(i == (int)pass.size()-1){
                ans += shortest_path(start, p[m-1], pl);
            }
        }
        cout << fixed << setprecision(4);
        cout << ans << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 150
memory_kb: 3300
final_rank: 6

code_snippet: #include <iostream>
#include <iomanip>
#include <complex>
#include <vector>
#include <algorithm>
#include <cmath>
#include <array>
using namespace std;
const double EPS = 1e-10;
const double INF = 1e12;
const double PI = acos(-1);
#define EQ(n,m) (abs((n)-(m)) < EPS)
#define X real()
#define Y imag()

typedef complex<double> P;
typedef vector<P> VP;
struct L : array<P, 2>{
    L(const P& a, const P& b){ at(0)=a; at(1)=b; }
    L(){}
};

namespace std{
    bool operator < (const P& a, const P& b){
        return !EQ(a.X,b.X) ? a.X<b.X : a.Y+EPS<b.Y;
    }
    bool operator == (const P& a, const P& b){
        return abs(a-b) < EPS;
    }
}

double dot(P a, P b){
    return (conj(a)*b).X;
}
double cross(P a, P b){
    return (conj(a)*b).Y;
}
int ccw(P a, P b, P c){
    b -= a;
    c -= a;
    if(cross(b,c) > EPS) return +1; //ccw
    if(cross(b,c) < -EPS) return -1; //cw
    if(dot(b,c) < -EPS) return +2; //c-a-b
    if(abs(c)-abs(b) > EPS) return -2; //a-b-c
    return 0; //a-c-b
}

bool intersectSS(const L& a, const L& b){
    return ( ccw(a[0],a[1],b[0]) *ccw(a[0],a[1],b[1]) <= 0 ) &&
        ( ccw(b[0],b[1],a[0]) *ccw(b[0],b[1],a[1]) <= 0 );
}

double shortest_path(P begin, P end, vector<L> &pl){
    pl.insert(pl.begin(), L(begin, begin));
    pl.push_back(L(end, end));
    int n = pl.size();
    vector<vector<double> > dp(n, vector<double>(2, INF));
    dp[0][0] = 0;
    for(int i=0; i<n; i++){
        for(int j=i+1; j<n; j++){
            for(int s=0; s<2; s++){
                for(int t=0; t<2; t++){
                    L edge(pl[i][s], pl[j][t]);
                    bool ok = true;
                    for(int k=i+1; k<j; k++){
                        if(!intersectSS(edge, pl[k])){
                            ok = false;
                            break;
                        }
                    }
                    if(ok){
                        dp[j][t] = min(dp[j][t], dp[i][s] +abs(edge[1] -edge[0]));
                    }
                }
            }
        }
    }
    return dp[n-1][0];
}

int main(){
    while(1){
        int m,n;
        cin >> m >> n;
        if(m == 0) break;

        VP p(m), pin(n);
        P rot(cos(0.01), sin(0.01));//回転させとかないとバグる(要検証)
        for(int i=0; i<m; i++){
            double x,y;
            cin >> x >> y;
            p[i] = P(x, y)*rot;
        }
        for(int i=0; i<n; i++){
            double x,y;
            cin >> x >> y;
            pin[i] = P(x, y)*rot;
        }

        sort(pin.begin(), pin.end());
        vector<L> ls;
        for(int i=0; i<n; i++){
            P prev;
            if(i==0 || !EQ(pin[i].X, pin[i-1].X)){
                prev = P(pin[i].X, -1e4);
            }else{
                prev = pin[i-1];
            }
            ls.emplace_back(prev, pin[i]);
            if(i==n-1 || !EQ(pin[i].X, pin[i+1].X)){
                ls.emplace_back(pin[i], P(pin[i].X, 1e4));
            }
        }

        vector<int> pass;
        for(int i=0; i<m-1; i++){
            L line(p[i], p[i+1]);
            if(EQ(line[0].X, line[1].X)) continue;
            bool goR = line[0].X < line[1].X;
            int j = goR? 0: ls.size()-1;
            while((goR && j<(int)ls.size()) || (!goR && j>=0)){
                if(intersectSS(ls[j], line)){
                    if(pass.empty() || pass.back() != j){
                        pass.push_back(j);
                    }else{
                        pass.pop_back();
                    }
                }
                if(goR) j++;
                else j--;
            }
        }

        double ans = 0;
        P start = p[0];
        vector<L> pl;
        for(int i=0; i<(int)pass.size(); i++){
            if(i!=(int)pass.size()-1 && EQ(ls[pass[i]][0].X, ls[pass[i+1]][0].X)){
                P end;
                if(ls[pass[i]][0].Y < ls[pass[i+1]][0].Y){
                    end = ls[pass[i]][1];
                }else{
                    end = ls[pass[i]][0];
                }
                ans += shortest_path(start, end, pl);
                start = end;
                pl = vector<L>();
            }else{
                pl.push_back(ls[pass[i]]);
            }
            if(i == (int)pass.size()-1){
                ans += shortest_path(start, p[m-1], pl);
            }
        }
        cout << fixed << setprecision(4);
        cout << ans << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 150
memory_kb: 3296
final_rank: 5

code_snippet: #include<bits/stdc++.h>
using namespace std;

using F = double;

#define x first
#define y second
using Point = pair<F, F>;

#define from first
#define to second
using Segment = pair<Point, Point>;

const F INF = 1e6;
const F EPS = 1e-6;

int M, N;
vector<Point> S, P;

vector<Point> rotate(auto point, auto a) {
  for(auto& p: point) p = make_pair(p.x * cos(a) - p.y * sin(a), p.x * sin(a) + p.y * cos(a));
  return point;
}

F norm(auto p) {return p.x * p.x + p.y * p.y;}
F dot(auto a, auto b) {return a.x * b.x + a.y * b.y;}
F cross(auto a, auto b) {return a.x * b.y - a.y * b.x;}
int ccw(auto a, auto b, auto c) {
  b = Point(b.x - a.x, b.y - a.y);
  c = Point(c.x - a.x, c.y - a.y);
  if(cross(b, c) > 0) return 1;
  if(cross(b, c) < 0) return -1;
  if(dot(b, c) < 0) return 2;
  if(norm(b) < norm(c)) return -2;
  return 0;
}
bool intersect(auto s, auto t) {
  return    ccw(s.from, s.to, t.from) * ccw(s.from, s.to, t.to) <= 0
         && ccw(t.from, t.to, s.from) * ccw(t.from, t.to, s.to) <= 0;
}

vector<Segment> uyenimo(auto v) {
  vector<Segment> res;
  for(auto s: v) {
    if(res.empty()) {
      res.emplace_back(s);
    } else {
      if(res.back() == s) res.pop_back();
      else                res.emplace_back(s);
    }
  }
  return res;
}

vector<Segment> shrink() {
  vector<Segment> scratch(P.size());
  for(auto p: P) for(auto dy: {-INF, INF}) scratch.emplace_back(p, Point(p.x, p.y + dy));

  sort(begin(scratch), end(scratch));

  vector<Segment> res;
  for(auto i = 1; i < S.size(); ++i) {
    Segment s(S[i-1], S[i]);
    vector<Segment> add;
    for(auto t: scratch) if(intersect(s, t)) add.emplace_back(t);
    if(s.to.x < s.from.x) reverse(begin(add), end(add));
    res.insert(end(res), begin(add), end(add));
  }

  while(true) {
    auto pre = res.size();
    res = uyenimo(res);
    if(pre == res.size()) break;
  }

  return res;
}

F solve() {
  S = rotate(S, EPS);
  P = rotate(P, EPS);

  auto order = shrink();

  order.insert(begin(order), Segment(S.front(), Point(0, 0)));
  order.emplace_back(S.back(), Point(0, 0));
  vector<F> dp(order.size(), INF);
  dp[0] = 0;
  for(auto i = 0; i < order.size(); ++i) {
    for(auto j = i + 1; j < order.size(); ++j) {
      Segment nex(order[i].from, order[j].from);
      auto ok = true;
      for(auto k = i + 1; ok && k < j; ++k) {
        if(!intersect(nex, order[k])) ok = false;
        if(order[k].from.x == order[k+1].from.x) ok = false;
      }
      if(ok) dp[j] = min(dp[j], dp[i] + hypot(nex.from.x - nex.to.x, nex.from.y - nex.to.y));
    }
  }

  return dp.back();
}

int main() {
  while(cin >> M >> N, M | N) {
    S = vector<Point>(M);
    for(auto& i: S) cin >> i.x >> i.y;
    P = vector<Point>(N);
    for(auto& i: P) cin >> i.x >> i.y;

    cout << setprecision(10) << fixed << solve() << endl;
  }
}
accuracy: 1
time_ms: 810
memory_kb: 3704
final_rank: 7

code_snippet: #include <bits/stdc++.h>

const int N = 250;
const double eps = 1e-9;
const double INF = 1e200;

int n, m;
struct Point {
	double x, y;
	
	Point() {}
	Point(double x, double y):x(x), y(y) {}
	
	void print() {
		printf("(%.2f, %.2f)\n", x, y);
	}
	
	friend Point operator + (const Point &a, const Point &b) {
		return Point(a.x + b.x, a.y + b.y);
	}
	
	friend Point operator - (const Point &a, const Point &b) {
		return Point(a.x - b.x, a.y - b.y);
	}
	
	friend Point operator * (const Point &a, const double &b) {
		return Point(a.x * b, a.y * b);
	}
};
Point string[N], pin[N];

int dcmp(double x) {
	if (std::abs(x) < eps) {
		return 0;
	}
	return x < 0 ? -1 : 1;
}

double cross(Point a, Point b) {
	return a.x * b.y - a.y * b.x;
}

double dot(Point a, Point b) {
	return a.x * b.x + a.y * b.y;
}

double getAngle(Point o, Point a, Point b) {
	return std::atan2(cross(a - o, b - o), dot(a - o, b - o));
}

double area(Point a, Point b, Point c) {
	return std::abs(cross(b - a, c - a)) / 2.0;
}

double sqr(double x) {
	return x * x;
}

double dist(Point a, Point b) {
	return std::sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));
}

bool inTriangle(Point p, Point a, Point b, Point c) {
	return dcmp(area(p, a, b) + area(p, b, c) + area(p, c, a) - area(a, b, c)) == 0
	&& dcmp(area(p, a, b)) == dcmp(area(p, b, c)) && dcmp(area(p, a, b)) == dcmp(area(p, a, c))
	;
}

Point getIntersection(Point p, Point v, Point q, Point w) {
	v = v - p;
	w = w - q;
	Point u = p - q;
	double t = cross(w, u) / cross(v, w);
	return p + (v * t);
}

void init() {
	for (int i = 1; i <= n; i ++) {
		double x, y;
		scanf("%lf%lf", &x, &y);
		string[i] = Point(x, y);
	}
	for (int i = 1; i <= m; i ++) {
		double x, y;
		scanf("%lf%lf", &x, &y);
		pin[i] = Point(x, y);
	}
}

void work() {
	std::vector<Point> answer;
	std::vector<double> exAngle;
	Point last, mid;
	
	answer.push_back(string[1]);
	last = string[1], mid = string[2];
	exAngle.push_back(INF);
	for (int i = 3; i <= n; i ++) {
		while (true) {
			double minAngle = getAngle(last, string[i], mid);
			Point tmp = string[i];
			bool tag = false;
			for (int j = 1; j <= m; j ++) {
				if (inTriangle(pin[j], last, mid, string[i])) {
					if (std::abs(getAngle(last, pin[j], mid)) < std::abs(minAngle)) {
						tag = true;
						minAngle = getAngle(last, pin[j], mid);
						tmp = pin[j];
					}
				}
			}
			if (dcmp(exAngle.back()) * dcmp(exAngle.back() + minAngle) == -1) {
				answer.pop_back();
				exAngle.pop_back();
				mid = getIntersection(answer.back(), last, mid, string[i]);
				last = answer.back();
			} else {
				exAngle.back() += minAngle;
				if (tag == false) {
					mid = string[i];
					break;
				}
				mid = getIntersection(last, tmp, mid, string[i]);
				answer.push_back(tmp);
				exAngle.push_back(0);
				last = tmp;
			}
		}
		/*
		printf("i = %d:\n", i);
		for (int j = 0; j < (int)answer.size(); j ++) {
			answer[j].print();
		}
		*/
	}
	answer.push_back(string[n]);
	
	double length = 0;
	for (int i = 1; i < (int)answer.size(); i ++) {
		length += dist(answer[i - 1], answer[i]);
	}
	printf("%.10f\n", length);
}

int main() {
	//freopen("input.txt", "r", stdin);
	
	while (std::cin >> n >> m && !(n == 0 && m == 0)) {
		init();
		work();
	}
	
	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1396
final_rank: 1

code_snippet: #include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<(int)(n);i++)
#define rep1(i,n) for(int i=1;i<=(int)(n);i++)
#define all(c) c.begin(),c.end()
#define pb push_back
#define fs first
#define sc second
#define show(x) cout << #x << " = " << x << endl
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)
using namespace std;
typedef double D;
typedef complex<D> P;
int K,N;
P ps[100],as[100];
bool up(P s,P t,P p){			//line over point
	D sx=s.real(),tx=t.real(),sy=s.imag(),ty=t.imag(),x=p.real(),y=p.imag();
	D ly=sy+(ty-sy)/(tx-sx)*(x-sx);
	return ly>y;
}
void addpath(vector<int>& vc,P s,P t){
	vector<int> ad;
	D sx=s.real(),tx=t.real(),sy=s.imag(),ty=t.imag();
	bool sw=0;
	if(sx>tx){
		sw=1;
		swap(sx,tx);
		swap(sy,ty);
	}
	rep(i,N){
		D x=as[i].real(),y=as[i].imag();
		if(sx<x&&x<tx){
			if(up(s,t,as[i])) ad.pb(i*2);
			else ad.pb(i*2+1);
		}
	}
	if(sw) reverse(all(ad));
	vc.insert(vc.end(),all(ad));
}
bool cancel(vector<int>& vc){
	bool update=0;
	int A=vc.size();
	vector<bool> gomi(A,0);
	rep(i,A-1){
		if(vc[i]==vc[i+1]){
			gomi[i]=gomi[i+1]=1;
			update=1;
			i++;
		}
	}
	vector<int> nvc;
	rep(i,A) if(!gomi[i]) nvc.pb(vc[i]);
	vc=nvc;
	return update;
}
P point(int id){
	return as[id/2];
}
D calclen(P S,P T,vector<int>& vc){
//	show(S);
//	show(T);
	int A=vc.size();
//	show(A);
//	for(int v:vc) cout<<v<<" ";
//	puts("");
	D dp[110];
	rep(i,A+2) dp[i]=1e9;
	dp[0]=0;
	rep(i,A+1){
		P t=(i==A?T:point(vc[i]));
		rep(j,i+1){
			P s=(j==0?S:point(vc[j-1]));
			bool ok=1;
			for(int k=j;k<i;k++){
				if(up(s,t,point(vc[k]))==(vc[k]&1)){
					ok=0;
					break;
				}
			}
			if(ok) chmin(dp[i+1],dp[j]+abs(s-t));
		}
	}
	return dp[A+1];
}
int main(){
	while(true){
		cin>>K>>N;
		if(K==0) break;
		rep(i,K){
			D x,y;
			cin>>x>>y;
			ps[i]=P(x,y)*polar(1.0,1.0);
		}
		rep(i,N){
			D x,y;
			cin>>x>>y;
			as[i]=P(x,y)*polar(1.0,1.0);
		}
		rep(i,N-1) rep(j,N-1) if(as[j].real()>as[j+1].real()) swap(as[j],as[j+1]);
		vector<int> vc;
		rep(i,K-1) addpath(vc,ps[i],ps[i+1]);
		while(cancel(vc));
		D ans=0;
		int M=vc.size();
		int l=-1;
		for(int r=1;r<=M;r++){
			if(r==M||(vc[r]^vc[r-1])==1){
				vector<int> tmp;
				P s,t;
				if(l==-1) s=ps[0];
				else s=point(vc[l]);
				if(r==M) t=ps[K-1];
				else t=point(vc[r]);
				if(r==M) r++;
				for(int i=l+1;i<r-1;i++) tmp.pb(vc[i]);
				ans+=calclen(s,t,tmp);
//				show(calclen(s,t,tmp));
				l=r;
			}
		}
		printf("%.12f\n",ans);
	}
}
accuracy: 1
time_ms: 20
memory_kb: 3308
final_rank: 4

code_snippet: #include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <vector>
#include <map>
#include <complex>
#include <queue>
#include <sstream>
#include <stack>

using namespace std;
typedef double R;
typedef complex<R> P;
typedef pair<P,P> L;
typedef pair<P,R> C;
typedef vector<P> Poly;
#define x real()
#define y imag()
const R PI = acos(-1);
const R EPS = 1e-9;
inline bool near(const P& p,const P& q){ return abs(p-q)<EPS;}
R dot(const P& p,const P& q){ return p.x*q.x+p.y*q.y;}
R det(const P& p,const P& q){ return p.x*q.y-p.y*q.x;}
enum LPposit{
  P_CD = -2, //counter direction
  P_CW = -1, //clock wise
  P_OS = 0, //on segment
  P_CCW = 1, //counter clock wise
  P_D = 2 //direction
};
inline R ccw_b(const P& p,const P& q,const P& r){  return det(q-p,r-p);}
LPposit ccw(const P& p, const P& q, const P& r){
  R c = ccw_b(p,q,r);
  if(c<-EPS) return P_CW;
  if(c>EPS) return P_CCW;
  if(dot(q-p,r-p)<-EPS) return P_CD;
  if(dot(p-q,r-q)<-EPS) return P_D;
  return P_OS;
}
inline R Sabs(const L& l){ return abs(l.first-l.second);}
inline R LPdist(const L& l,const P& p){ return abs(ccw_b(l.first,l.second,p))/Sabs(l);}
inline R SPdist(L l,P p){
  R a = abs(l.first-p);
  R b = abs(l.second-p);
  R c = Sabs(l);
  if(b*b+c*c>a*a && a*a+c*c>b*b) return LPdist(l,p);
  return min(a,b);
}
bool crossS(const L& p,const L& q){
  return
    ccw(p.first,p.second,q.first)*ccw(p.first,p.second,q.second)<=0 &&
    ccw(q.first,q.second,p.first)*ccw(q.first,q.second,p.second)<=0;
}
P intersect(const L& p,const L& q){
  P vp = p.second-p.first;
  P vq = q.second-q.first;
  P c(det(vp,p.first), det(vq,q.first));
  return P(det(c, P(vp.x, vq.x)), det(c, P(vp.y, vq.y))) / det(vp, vq);
}

int inConvex(const Poly& ps, P p){
  int n = ps.size();
  int c = ccw(ps[n-1],p,ps[0]);
  for(int i=0;i+1<n;++i)
    if(ccw(ps[i],p,ps[i+1])!=c) return false;
  return true;
}

vector<P> incP(const vector<P>& v,const Poly& pol){ //pol?????????????????????v???????´??????????
  int n = v.size();
  vector<P> ret;
  for(int i=0;i<n;++i) if(inConvex(pol,v[i])==1) ret.push_back(v[i]);
  return ret;
}

vector<P> himo;
vector<P> kugi;

double input(){
  double ret;
  cin >> ret;
  return ret;
}

R angle(const P& a,const P& b){
  int sgn = (det(a,b)>=0)?1:-1;
  return acos(dot(a,b)/abs(a)/abs(b))*sgn;
}

struct D{
  P p,pre;
  R deg; //????????????????§????
  D(P a,P b,R d):p(a),pre(b),deg(d){}
};

P nextKugi(const Poly& pol,vector<P> tmp){
  P s = pol[0];
  P v1=pol[1]-s, v2=pol[2]-s;
  double argmin = abs(angle(v1,v2));
  vector<P> ps = incP(tmp,pol);
  int n = ps.size();
  P nxt = 0;
  bool found = false;
  for(int i=0;i<n;++i){
    double ag = abs(angle(v1,ps[i]-s));
    if(ag < argmin){
      found = true;
      argmin = ag;
      nxt = ps[i];
    }
  }
  if(!found) return P(-1,-1);
  return nxt;
}

vector<P> path(vector<P> ps,const Poly& pol){ //pol???????§???¢, v???pol??????????????????
  P s = pol[0];
  vector<P> ret;
  while(true){
    int n = ps.size();
    P v1 = pol[1]-s, v2=pol[2]-s;
    double argmin = abs(angle(v1,v2));
    P nxt = 0;
    bool found = false;
    for(int i=0;i<n;++i){
      if(ps[i]==s) continue;
      double ag = abs(angle(v1,ps[i]-s));
      if(ag < argmin){
	found = true;
	argmin = ag;
	nxt = ps[i];
      }
    }
    if(!found) break;
    ret.push_back(nxt);
    vector<P> tmp;
    Poly POL = pol; POL[0]=nxt;
    for(int i=0;i<n;++i)
      if(inConvex(POL,ps[i])) tmp.push_back(ps[i]);
    ps = tmp;
    s = nxt;
  }
  return ret;
}


R solve(){
  if(himo.size()==2) return abs((himo[1]-himo[0]));
  P A = himo[0];
  P B = himo[1];
  stack<D> St;
  int n = himo.size();
  for(int i=2;i<n;++i){
    P C = himo[i];
    while(!St.empty()){
      Poly ABC(3);
      ABC[0]=A, ABC[1]=B, ABC[2]=C;
      P K = nextKugi(ABC,kugi);
      if(K==P(-1,-1)) K = C;
      D X = St.top(); St.pop();
      double nxtdeg = X.deg+angle(B-A,K-A);
      if(X.deg * nxtdeg < 0){
	B = intersect(L(X.pre,X.p), L(B,C));
	A = X.pre;
      }
      else{
	X.deg = nxtdeg;
	St.push(X);
	break;
      }
    }

    Poly ABC(3); ABC[0]=A, ABC[1]=B, ABC[2]=C;
    vector<P> ins = incP(kugi,ABC);
    vector<P> ps = path(ins,ABC);
    ps.push_back(C);
    for(int j=0;j+1<ps.size();++j){
      St.push(D(ps[j], A, angle(ps[j]-A, ps[j+1]-ps[j])));
      A = ps[j];
    }
    B = C;
  }

  vector<P> X;
  X.push_back(himo[n-1]);
  while(!St.empty()){
    X.push_back(St.top().p);
    St.pop();
  }
  X.push_back(himo[0]);
  reverse(X.begin(), X.end());
  
  ofstream ofs("1164.dat");
  for(int i=0;i<X.size();++i) ofs << X[i].x << " " << X[i].y << endl;

  R ret = 0;
  for(int i=0;i+1<X.size();++i) ret+=abs(X[i+1]-X[i]);
  return ret;
}

int main(){
  int n,m;
  while(cin>>m>>n,m||n){
    himo.clear();
    kugi.clear();
    ofstream ofsh("himo.dat");
    ofstream ofsk("kugi.dat");
    for(int i=0;i<m;++i)
      himo.push_back(P(input(),input()));
    for(int i=0;i<n;++i)
      kugi.push_back(P(input(),input()));

    for(int i=0;i<m;++i)
      ofsh<<himo[i].x << " " << himo[i].y << endl;
    for(int i=0;i<n;++i)
      ofsk<<kugi[i].x << " " << kugi[i].y << endl;
    
    cout << fixed << setprecision(10) << solve() << endl;
  }
  return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 1464
final_rank: 3

code_snippet: #include<cstdio>
#include<complex>
#include<cmath>
#include<vector>
#include<algorithm>

using namespace std;

typedef double Real;
typedef complex<Real> Point;

bool cmp(const Point &p1,const Point &p2){
	return p1.real()<p2.real();
}

Real sx[110],sy[110];
Real nx[110],ny[110];
int N,M;

Point ns[110];

vector<int> vec;

void init(){
	vec.clear();
}

void rot(){
	for(int i=1;i<M;i++){
		sx[i]-=sx[0];
		sy[i]-=sy[0];
	}
	for(int i=0;i<N;i++){
		nx[i]-=sx[0];
		ny[i]-=sy[0];
	}
	sx[0]=0,sy[0]=0;
	Point coe=Point(cos(1),sin(1));
//	Point coe=1;
	for(int i=1;i<M;i++){
		Point tmp=Point(sx[i],sy[i]);
		tmp*=coe;
		sx[i]=tmp.real();
		sy[i]=tmp.imag();
	}
	for(int i=0;i<N;i++){
		Point tmp=Point(nx[i],ny[i]);
		tmp*=coe;
		nx[i]=tmp.real();
		ny[i]=tmp.imag();
	}
	for(int i=0;i<N;i++){
		ns[i]=Point(nx[i],ny[i]);
	}
	sort(ns,ns+N,cmp);
	for(int i=0;i<N;i++){
		nx[i]=ns[i].real();
		ny[i]=ns[i].imag();
	}
}

void calc(Real sx,Real sy,Real tx,Real ty){
//	printf("%f %f %f %f\n",sx,sy,tx,ty);
	if(sx<tx){
		for(int i=0;i<N;i++){
			if(sx<nx[i]&&nx[i]<tx){
				Real r=(nx[i]-sx)/(tx-sx);
				Real dy=(ty-sy)*r;
				Real y=sy+dy;
				int id;
				if(y<ny[i]) id=i*2;
				else id=i*2+1;
//				printf("id=%d\n",id);
				if(vec.size()==0||vec.back()!=id) vec.push_back(id);
				else vec.pop_back();
			}
		}
	}else{
		for(int i=N-1;i>=0;i--){
			if(tx<nx[i]&&nx[i]<sx){
				Real r=(nx[i]-sx)/(tx-sx);
				Real dy=(ty-sy)*r;
				Real y=sy+dy;
				int id;
				if(y<ny[i]) id=i*2;
				else id=i*2+1;
//				printf("id=%d\n",id);
				if(vec.size()==0||vec.back()!=id) vec.push_back(id);
				else vec.pop_back();
			}
		}
	}
}

Real dp[10100];

Point ps[10100];
bool dirs[10100];

Real solve(){
	init();
	rot();
	for(int i=0;i<M-1;i++){
		calc(sx[i],sy[i],sx[i+1],sy[i+1]);
	}
	if(vec.size()==0){
		Real dx=sx[0]-sx[M-1],dy=sy[0]-sy[M-1];
		return sqrt(dx*dx+dy*dy);
	}
	ps[0]=Point(sx[0],sy[0]);
	for(int i=0;i<vec.size();i++){
		ps[i+1]=ns[vec[i]/2];
		dirs[i+1]=vec[i]%2==1;
	}
	ps[vec.size()+1]=Point(sx[M-1],sy[M-1]);
	dp[0]=0;
//	for(int i=0;i<vec.size()+2;i++){
//		printf("%f %f %c\n",ps[i].real(),ps[i].imag(),dirs[i]?'u':'d');
//	}
	for(int i=1;i<vec.size()+2;i++){
		dp[i]=dp[i-1]+abs(ps[i]-ps[i-1]);
		for(int j=i-2;j>=0;j--){
			if(dp[i]<dp[j]+abs(ps[i]-ps[j])) continue;
			if(abs(ps[j]-ps[j+1])<(1e-8)) break;
			bool ok=true;
			for(int k=j+1;k<i;k++){
				Real x1=ps[j].real(),y1_=ps[j].imag();
				Real x2=ps[i].real(),y2_=ps[i].imag();
				Real x=ps[k].real();
				Real r=(x-x1)/(x2-x1);
				Real y=y1_+(y2_-y1_)*r;
				bool flg=ps[k].imag()<y;
				if(dirs[k]!=flg){
					ok=false;
					break;
				}
			}
			if(ok){
				dp[i]=dp[j]+abs(ps[i]-ps[j]);
			}
		}
	}
//	for(int i=0;i<vec.size()+2;i++){
//		printf("%f ",dp[i]);
//	}
//	printf("\n");
	return dp[vec.size()+1];
}

void input(){
	scanf("%d%d",&M,&N);
	if(M==0&&N==0) exit(0);
	for(int i=0;i<M;i++){
		scanf("%lf%lf",sx+i,sy+i);
	}
	for(int i=0;i<N;i++){
		scanf("%lf%lf",nx+i,ny+i);
	}
}

int main(){
	while(true){
		input();
		Real ans=solve();
		printf("%f\n",ans);
	}
	return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 1352
final_rank: 2

code_snippet: #include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <iostream>
#include <complex>
using namespace std;
typedef long long int ll;
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;

#define REP(i,x) for(int i=0;i<(int)(x);i++)
#define REPS(i,x) for(int i=1;i<=(int)(x);i++)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();i++)
#define RFOR(i,c) for(__typeof((c).rbegin())i=(c).rbegin();i!=(c).rend();i++)
#define ALL(container) (container).begin(), (container).end()
#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );

namespace geom{
#define X real()
#define Y imag()
#define at(i) ((*this)[i])
#define SELF (*this)
	enum {TRUE = 1, FALSE = 0, BORDER = -1};
	typedef int BOOL;
	typedef double R;
	const R INF = 1e8;
	R EPS = 1e-8;
	inline int sig(const R &x) { return (abs(x) < EPS ? 0 : x > 0 ? 1 : -1); }
	inline BOOL less(const R &x, const R &y) {return sig(x-y) ? x < y : BORDER;}
	typedef complex<R> P;
	inline R norm(const P &p){return p.X*p.X+p.Y*p.Y;}
	inline R inp(const P& a, const P& b){return (conj(a)*b).X;}
	inline R outp(const P& a, const P& b){return (conj(a)*b).Y;}
	
	struct L : public vector<P>{	// line
		L(const P &p1, const P &p2){this->push_back(p1);this->push_back(p2);}
		L(){}
		P dir()const {return at(1) - at(0);}
		BOOL online(const P &p)const {return !sig(outp(p-at(0), dir()));}
	};
	struct S : public L{
		S(const P &p1, const P &p2):L(p1, p2){}
		S(){}
		BOOL online(const P &p)const {
			return inp(p-at(0), dir()) > EPS && inp(p-at(1), -dir()) > -EPS;
		}
	};
	inline P crosspoint(const L &l, const L &m){
		R A = outp(l.dir(), m.dir()), B = outp(l.dir(), l[1] - m[0]);
		if(!sig(abs(A)) && !sig(abs(B))) return m[0];
		return m[0] + B / A * (m[1] - m[0]);
	}

#undef SELF
#undef at
}

using namespace geom;

int f = 0;
namespace std{
	bool operator<(const P &a, const P &b){return sig(a.X-b.X) ? a.X < b.X : a.Y+EPS < b.Y;}
	bool operator==(const P &a, const P &b){return abs(a-b) < EPS;}
	istream& operator>>(istream &is, P &p){R x,y;is>>x>>y;p=P(x, y);return is;}
}

int n, m;

vi path(S root, const vector<P>& pin){
	vi res;
	if(!sig(root.dir().X)) return res;
	REPS(i, n){
		P cp = crosspoint(root, L(pin[i], pin[i]+P(0, 1)));
		if(root.online(cp) == FALSE) continue;
		if(abs(root[0].X - cp.X) < EPS || abs(root[1].X - cp.X) < EPS) continue;
		res.push_back(pin[i].Y < cp.Y ? i : -i);
	}
	sort(ALL(res), [&](int i, int j){
		return abs(root[0].X - pin[abs(i)].X) < abs(root[0].X - pin[abs(j)].X);
	});
	return res;
}

int main(int argc, char *argv[]){
	ios::sync_with_stdio(false);
	int T = 1;
	while(cin >> m >> n, n){
		vector<P> root(m), pin(n+1);
		REP(i, m){
			cin >> root[i];
			root[i] *= polar((R)1, (R)1);
		}
		pin[0] = root[0];
		REPS(i, n){
			cin >> pin[i];
			pin[i] *= polar((R)1, (R)1);
		}
		sort(pin.begin()+1, pin.end());
		pin.push_back(root.back());
		vector<int> st;
		st.push_back(0);
		REP(i, m-1){
			S s(root[i], root[i+1]);
			vi isc = path(s, pin);
			FOR(it, isc){
				if(st.back() == *it) st.pop_back();
				else st.push_back(*it);
			}
		}
		st.push_back(n+1);
		
		vector<R> dp(st.size(), INF);
		dp[0] = .0;
		int save = 0;
		REP(i, st.size()){
			if(i && st[i] == -st[i-1]){
				save = i;
				dp[i] = dp[i-1];
				continue;
			}
			for(int j=save;j<i;j++){
				S r(pin[abs(st[j])], pin[abs(st[i])]);
				if(dp[i] < dp[j] + abs(r.dir())+EPS) continue;
				vi pt = path(r, pin);
				if([&](){
					for(int k=1;k<=pt.size()&&j+k<i;k++) if(pt[k-1] != st[j+k]) return 0;
					return 1;
				}()) dp[i] = dp[j] + abs(r.dir());
			}
		}
		printf("%.10f\n", (double)dp.back());
	}
	return 0;
}
accuracy: 1
time_ms: 3160
memory_kb: 1376
final_rank: 9

code_snippet: #include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <climits>
#include <ctime>
#include <queue>
#include <stack>
#include <algorithm>
#include <list>
#include <vector>
#include <set>
#include <map>
#include <iostream>
#include <deque>
#include <complex>
#include <string>
#include <iomanip>
#include <sstream>
#include <bitset>
#include <valarray>
#include <unordered_map>
#include <iterator>
#include <assert.h>
using namespace std;
typedef long long int ll;
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;

#define REP(i,x) for(int i=0;i<(int)(x);i++)
#define REPS(i,x) for(int i=1;i<=(int)(x);i++)
#define RREP(i,x) for(int i=((int)(x)-1);i>=0;i--)
#define RREPS(i,x) for(int i=((int)(x));i>0;i--)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();i++)
#define RFOR(i,c) for(__typeof((c).rbegin())i=(c).rbegin();i!=(c).rend();i++)
#define ALL(container) (container).begin(), (container).end()
#define RALL(container) (container).rbegin(), (container).rend()
#define SZ(container) ((int)container.size())
#define mp(a,b) make_pair(a, b)
#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );

template<class T> bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T> bool chmin(T &a, const T &b) { if (a>b) { a=b; return 1; } return 0; }
template<class T> ostream& operator<<(ostream &os, const vector<T> &t) {
os<<"["; FOR(it,t) {if(it!=t.begin()) os<<","; os<<*it;} os<<"]"; return os;
}
template<class T> ostream& operator<<(ostream &os, const set<T> &t) {
os<<"{"; FOR(it,t) {if(it!=t.begin()) os<<","; os<<*it;} os<<"}"; return os;
}
template<class S, class T> ostream& operator<<(ostream &os, const pair<S,T> &t) { return os<<"("<<t.first<<","<<t.second<<")";}
template<class S, class T> pair<S,T> operator+(const pair<S,T> &s, const pair<S,T> &t){ return pair<S,T>(s.first+t.first, s.second+t.second);}
template<class S, class T> pair<S,T> operator-(const pair<S,T> &s, const pair<S,T> &t){ return pair<S,T>(s.first-t.first, s.second-t.second);}

namespace geom{
#define X real()
#define Y imag()
#define at(i) ((*this)[i])
#define SELF (*this)
	enum {TRUE = 1, FALSE = 0, BORDER = -1};
	typedef int BOOL;
	typedef double R;
	const R INF = 1e8;
	R EPS = 1e-8;
	const R PI = 3.1415926535897932384626;
	inline int sig(const R &x) { return (abs(x) < EPS ? 0 : x > 0 ? 1 : -1); }
	inline BOOL less(const R &x, const R &y) {return sig(x-y) ? x < y : BORDER;}
	typedef complex<R> P;
	inline R norm(const P &p){return p.X*p.X+p.Y*p.Y;}
	inline R inp(const P& a, const P& b){return (conj(a)*b).X;}
	inline R outp(const P& a, const P& b){return (conj(a)*b).Y;}
	inline P unit(const P& p){return p/abs(p);}
	inline P proj(const P &s, const P &t){return t*inp(s, t)/norm(t);}
	inline int ccw(const P &s, const P &t, const P &p, int adv=0){
		int res = sig(outp(t-s, p-s));
		if(res || !adv) return res;
		if(sig(inp(t-s, p-s)) < 0) return -2;	// p-s-t
		if(sig(inp(s-t, p-t)) < 0) return 2;	// s-t-p
		return 0;								// s-p-t
	}
	
	
	struct L : public vector<P>{	// line
		L(const P &p1, const P &p2){this->push_back(p1);this->push_back(p2);}
		L(){}
		P dir()const {return at(1) - at(0);}
		BOOL online(const P &p)const {return !sig(outp(p-at(0), dir()));}
	};
	struct S : public L{	// segment
		S(const P &p1, const P &p2):L(p1, p2){}
		S(){}
		BOOL online(const P &p)const {
			if(!sig(norm(p - at(0))) || !sig(norm(p - at(1)))) return BORDER;
			// 座標の二乗とEPSの差が大きすぎないように注意
			return !sig(outp(p-at(0), dir())) && inp(p-at(0), dir()) > EPS && inp(p-at(1), -dir()) > -EPS;
			//return !sig(abs(at(0)-p) + abs(at(1) - p) - abs(at(0) - at(1)));
		}
	};
	inline P proj(const P &s, const L &t){return t[0] + proj(s-t[0], t[1]-t[0]);}
	inline P reflect(const P &s, const L &t){return (R)2.*proj(s, t) - s;}
	inline S reflect(const S &s, const L &t){return S(reflect(s[0], t), reflect(s[1], t));}
	BOOL intersect(const S &s, const L &l){
		if(l.online(s[0]) || l.online(s[1])) return BORDER;
		return (sig(outp(l.dir(), s[0]-l[0])) * sig(outp(l.dir(), s[1]-l[0])) <= 0);
	}
	inline P crosspoint(const L &l, const L &m){
		R A = outp(l.dir(), m.dir()), B = outp(l.dir(), l[1] - m[0]);
		if(!sig(abs(A)) && !sig(abs(B))) return m[0]; // same line
		if(abs(A) < EPS) assert(false); // !!!PRECONDITION NOT SATISFIED!!!
		return m[0] + B / A * (m[1] - m[0]);
	}

#undef SELF
#undef at
}

using namespace geom;

int f = 0;
namespace std{
	bool operator<(const P &a, const P &b){return sig(a.X-b.X) ? a.X < b.X : a.Y+EPS < b.Y;}
	bool operator==(const P &a, const P &b){return abs(a-b) < EPS;}
	istream& operator>>(istream &is, P &p){R x,y;is>>x>>y;p=P(x, y);return is;}
}

int n, m;

vi path(S root, const vector<P>& pin){
	vi res;
	if(!sig(root.dir().X)) return res;
	REPS(i, n){
		P cp = crosspoint(root, L(pin[i], pin[i]+P(0, 1)));
		if(root.online(cp) == FALSE) continue;
		if(abs(root[0].X - cp.X) < EPS || abs(root[1].X - cp.X) < EPS) continue;
		res.push_back(pin[i].Y < cp.Y ? i : -i);
	}
	sort(ALL(res), [&](int i, int j){
		return abs(root[0].X - pin[abs(i)].X) < abs(root[0].X - pin[abs(j)].X);
	});
	return res;
}

int main(int argc, char *argv[]){
	ios::sync_with_stdio(false);
	int T = 1;
	while(cin >> m >> n, n){
		vector<P> root(m), pin(n+1);
		REP(i, m){
			cin >> root[i];
			root[i] *= polar((R)1, (R)1);
		}
		pin[0] = root[0];
		REPS(i, n){
			cin >> pin[i];
			pin[i] *= polar((R)1, (R)1);
		}
		sort(pin.begin()+1, pin.end());
		pin.push_back(root.back());
		vector<int> st;
		st.push_back(0);
		REP(i, m-1){
			S s(root[i], root[i+1]);
			vi isc = path(s, pin);
			FOR(it, isc){
				if(st.back() == *it) st.pop_back();
				else st.push_back(*it);
			}
		}
		st.push_back(n+1);
		
		vector<R> dp(st.size(), INF);
		dp[0] = .0;
		int save = 0;
		REP(i, st.size()){
			if(i && st[i] == -st[i-1]){
				save = i;
				dp[i] = dp[i-1];
				continue;
			}
			for(int j=save;j<i;j++){
				S r(pin[abs(st[j])], pin[abs(st[i])]);
				vi pt = path(r, pin);
				if([&](){
					for(int k=1;k<=pt.size()&&j+k<i;k++) if(pt[k-1] != st[j+k]) return 0;
					return 1;
				}()) chmin(dp[i], dp[j] + abs(r.dir()));
			}
		}
		printf("%.10f\n", (double)dp.back());
	}
	return 0;
}
accuracy: 1
time_ms: 4570
memory_kb: 1376
final_rank: 11

code_snippet: #include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <climits>
#include <ctime>
#include <queue>
#include <stack>
#include <algorithm>
#include <list>
#include <vector>
#include <set>
#include <map>
#include <iostream>
#include <deque>
#include <complex>
#include <string>
#include <iomanip>
#include <sstream>
#include <bitset>
#include <valarray>
#include <unordered_map>
#include <iterator>
#include <assert.h>
using namespace std;
typedef long long int ll;
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;

#define REP(i,x) for(int i=0;i<(int)(x);i++)
#define REPS(i,x) for(int i=1;i<=(int)(x);i++)
#define RREP(i,x) for(int i=((int)(x)-1);i>=0;i--)
#define RREPS(i,x) for(int i=((int)(x));i>0;i--)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();i++)
#define RFOR(i,c) for(__typeof((c).rbegin())i=(c).rbegin();i!=(c).rend();i++)
#define ALL(container) (container).begin(), (container).end()
#define RALL(container) (container).rbegin(), (container).rend()
#define SZ(container) ((int)container.size())
#define mp(a,b) make_pair(a, b)
#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );

template<class T> bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T> bool chmin(T &a, const T &b) { if (a>b) { a=b; return 1; } return 0; }
template<class T> ostream& operator<<(ostream &os, const vector<T> &t) {
os<<"["; FOR(it,t) {if(it!=t.begin()) os<<","; os<<*it;} os<<"]"; return os;
}
template<class T> ostream& operator<<(ostream &os, const set<T> &t) {
os<<"{"; FOR(it,t) {if(it!=t.begin()) os<<","; os<<*it;} os<<"}"; return os;
}
template<class S, class T> ostream& operator<<(ostream &os, const pair<S,T> &t) { return os<<"("<<t.first<<","<<t.second<<")";}
template<class S, class T> pair<S,T> operator+(const pair<S,T> &s, const pair<S,T> &t){ return pair<S,T>(s.first+t.first, s.second+t.second);}
template<class S, class T> pair<S,T> operator-(const pair<S,T> &s, const pair<S,T> &t){ return pair<S,T>(s.first-t.first, s.second-t.second);}

namespace geom{
#define X real()
#define Y imag()
#define at(i) ((*this)[i])
#define SELF (*this)
	enum {TRUE = 1, FALSE = 0, BORDER = -1};
	typedef int BOOL;
	typedef double R;
	const R INF = 1e8;
	R EPS = 1e-8;
	const R PI = 3.1415926535897932384626;
	inline int sig(const R &x) { return (abs(x) < EPS ? 0 : x > 0 ? 1 : -1); }
	inline BOOL less(const R &x, const R &y) {return sig(x-y) ? x < y : BORDER;}
	typedef complex<R> P;
	inline R norm(const P &p){return p.X*p.X+p.Y*p.Y;}
	inline R inp(const P& a, const P& b){return (conj(a)*b).X;}
	inline R outp(const P& a, const P& b){return (conj(a)*b).Y;}
	inline P unit(const P& p){return p/abs(p);}
	inline P proj(const P &s, const P &t){return t*inp(s, t)/norm(t);}
	inline int ccw(const P &s, const P &t, const P &p, int adv=0){
		int res = sig(outp(t-s, p-s));
		if(res || !adv) return res;
		if(sig(inp(t-s, p-s)) < 0) return -2;	// p-s-t
		if(sig(inp(s-t, p-t)) < 0) return 2;	// s-t-p
		return 0;								// s-p-t
	}
	
	
	struct L : public vector<P>{	// line
		L(const P &p1, const P &p2){this->push_back(p1);this->push_back(p2);}
		L(){}
		P dir()const {return at(1) - at(0);}
		BOOL online(const P &p)const {return !sig(outp(p-at(0), dir()));}
	};
	struct S : public L{	// segment
		S(const P &p1, const P &p2):L(p1, p2){}
		S(){}
		BOOL online(const P &p)const {
			if(!sig(norm(p - at(0))) || !sig(norm(p - at(1)))) return BORDER;
			// 座標の二乗とEPSの差が大きすぎないように注意
			return !sig(outp(p-at(0), dir())) && inp(p-at(0), dir()) > EPS && inp(p-at(1), -dir()) > -EPS;
			//return !sig(abs(at(0)-p) + abs(at(1) - p) - abs(at(0) - at(1)));
		}
	};
	struct C : public P{
		C(){}
		C(const P& p, const R r):P(p), r(r){}
		R r;
		BOOL inside(const P& p)const { return less(norm(p-SELF), r*r);}
	};
	struct F : public C{
		R s, t;
		F(const C &c, R ss, R tt):C(c), s(ss), t(tt){
			if(PI < s) s -= 2*PI;
			if(PI < t) t -= 2*PI;
		}
		BOOL inside(const P& p)const {
			P v = p - SELF;
			if(!sig(norm(v))) return BORDER;
			R a = arg(v);
			if(t < s){
				if((!less(s, a) && !less(a, t)) || !less(norm(v), r*r)) return FALSE;
				return less(s, a) | less(a, t) | less(norm(v), r*r);
			}else{
				if(!less(s, a) || !less(a, t) || !less(norm(v), r*r)) return FALSE;
				return less(s, a) | less(a, t) | less(norm(v), r*r);
			}
		}
	};
	P crosspoint(const L &l, const L &m);
	struct G : public vector<P>{
		G(size_type size=0):vector(size){}
		S edge(int i)const {return S(at(i), at(i+1 == size() ? 0 : i+1));}
		BOOL contains(const P &p)const {
			R sum = .0;
			REP(i, size()){
				if(S(at(i), at((i+1)%size())).online(p)) return BORDER;	// online
				sum += arg((at(i) - p) / (at((i+1)%size()) - p));
			}
			return !!sig(sum);
		}
		R area()const {
			R sum = 0;
			REP(i, size()) sum += outp(at(i), at((i+1)%size()));
			return abs(sum / 2.);
		}
		P gp()const {
			P r(.0, .0);
			REP(i, size()){
				const S &s = edge(i);
				r += (s[0]+s[1])*outp(s[0], s[1]);
			}
			return r / (6*area());
		}
		G convex_hull(bool online = false) {
			if(size() < 2) return *this;
			sort(ALL(*this));
			G r;
			r.resize((int)size()*2);
			int k=0;
			for(int i=0;i<size();r[k++]=at(i++))
				while(k>1 && ccw(r[k-2], r[k-1], at(i)) < 1-online) k--;
			int t = k;
			for(int i=(int)size()-1;i>=0;r[k++]=at(i--))
				while(k>t && ccw(r[k-2], r[k-1], at(i)) < 1-online) k--;
			r.resize(k-1);
			return r;
		}
		G cut(const L &l)const {
			G g;
			REP(i, size()){
				const S &s = edge(i);
				if(ccw(l[0], l[1], s[0], 0) >= 0) g.push_back(s[0]);
				if(ccw(l[0], l[1], s[0], 0) * ccw(l[0], l[1], s[1], 0) < 0)
					g.push_back(crosspoint(s, l));
			}
			return g;
		}
		G Voronoi(const vector<P> &p, const int t)const {
			G g = *this;
			REP(i, p.size())if(i!=t){
				const P m = (p[t]+p[i])*(R)0.5;
				g = g.cut(L(m, m+(p[i]-p[t])*P(0, 1)));
			}
			return g;
		}
	};

	inline P proj(const P &s, const L &t){return t[0] + proj(s-t[0], t[1]-t[0]);}
	inline P reflect(const P &s, const L &t){return (R)2.*proj(s, t) - s;}
	inline S reflect(const S &s, const L &t){return S(reflect(s[0], t), reflect(s[1], t));}
	BOOL intersect(const S &s, const S &t){
		const int p = ccw(t[0], t[1], s[0], 1) * ccw(t[0], t[1], s[1], 1);
		const int q = ccw(s[0], s[1], t[0], 1) * ccw(s[0], s[1], t[1], 1);
		return (p>0||q>0) ? FALSE : (!p||!q) ? BORDER : TRUE;
	}
	BOOL intersect(const S &s, const L &l){
		if(l.online(s[0]) || l.online(s[1])) return BORDER;
		return (sig(outp(l.dir(), s[0]-l[0])) * sig(outp(l.dir(), s[1]-l[0])) <= 0);
	}
	R dist2(const L &l, const P &p){return norm(outp(l.dir(), p - l[0])) / norm(l.dir());}
	R dist2(const S &s, const P &p){
		if(inp(p-s[0],  s.dir()) < EPS) return norm(p - s[0]);
		if(inp(p-s[1], -s.dir()) < EPS) return norm(p - s[1]);
		return dist2((const L &)s, p);
	}
	R dist2(const S &s, const L &l){
		return intersect(s, l) ? .0 : min(dist2(l, s[0]), dist2(l, s[1]));
	}
	R dist2(const S &s, const S &t){
		return intersect(s, t) ? .0 : min(min(dist2(s, t[0]), dist2(t, s[0])), 
									   	  min(dist2(s, t[1]), dist2(t, s[1])));
	}
	template <class T> R dist2(const G &g, const T& t){ // todo: 内部に完全に含まれる場合
		R res = INF;
		REP(i, g.size()) res = min(res, dist2(g.edge(i), t));
		return res;
	}
	template<class S, class T> R dist(const S& s, const T& t){return sqrt(dist2(s, t));}
	inline BOOL intersect(const C &a, const C &b){
		return less((a.r-b.r)*(a.r-b.r), norm(a-b)) + less(norm(a-b), (a.r+b.r)*(a.r+b.r)) - 1;
	}
	inline BOOL intersect(const C &c, const L &l){
		return less(dist2(l, c), c.r*c.r);
	}
	inline BOOL intersect(const C &c, const S &s){
		int d = less(dist2(s, c), c.r*c.r);
		if(d != TRUE) return d;
		int p = c.inside(s[0]), q = c.inside(s[1]);
		return (p<0 || q<0) ? BORDER : p&q;
	}
	inline P crosspoint(const L &l, const L &m){
		R A = outp(l.dir(), m.dir()), B = outp(l.dir(), l[1] - m[0]);
		if(!sig(abs(A)) && !sig(abs(B))) return m[0]; // same line
		if(abs(A) < EPS) assert(false); // !!!PRECONDITION NOT SATISFIED!!!
		return m[0] + B / A * (m[1] - m[0]);
	}

#undef SELF
#undef at
}

using namespace geom;

int f = 0;
namespace std{
	bool operator<(const P &a, const P &b){return sig(a.X-b.X) ? a.X < b.X : a.Y+EPS < b.Y;}
	bool operator==(const P &a, const P &b){return abs(a-b) < EPS;}
	istream& operator>>(istream &is, P &p){R x,y;is>>x>>y;p=P(x, y);return is;}
	istream& operator>>(istream &is, L &l){l.resize(2);return is >> l[0] >> l[1];}
	istream& operator>>(istream &is, C &c){return is >> (P &)c >> c.r;}
	const R B = 200;
	const R Z = .5;
	ostream& operator<<(ostream &os, const C &c){return os << "circle("<<B+Z*(c.X)<<", "<<1000-B-Z*(c.Y)<<", "<<Z*(c.r)<<")";}
	ostream& operator<<(ostream &os, const P &p){return os << C(p, 2./Z);}
	ostream& operator<<(ostream &os, const S &s){return os << "line("<<B+Z*(s[0].X)<<", "<<1000-B-Z*(s[0].Y)<<", "<<B+Z*(s[1].X)<<", "<<1000-B-Z*(s[1].Y)<<")";}
	ostream& operator<<(ostream &os, const G &g){REP(i, g.size()) os << g.edge(i) << endl;return os;}

}

int n, m;

vi path(S root, const vector<P>& pin){
	vi res;
	if(!sig(root.dir().X)) return res;
	REPS(i, n){
		P cp = crosspoint(root, L(pin[i], pin[i]+P(0, 1)));
		if(root.online(cp) == FALSE) continue;
		if(abs(root[0].X - cp.X) < EPS || abs(root[1].X - cp.X) < EPS) continue;
		res.push_back(pin[i].Y < cp.Y ? i : -i);
	}
	sort(ALL(res), [&](int i, int j){
		return abs(root[0].X - pin[abs(i)].X) < abs(root[0].X - pin[abs(j)].X);
	});
	return res;
}

int main(int argc, char *argv[]){
	ios::sync_with_stdio(false);
	int T = 1;
	while(cin >> m >> n, n){
		vector<P> root(m), pin(n+1);
		REP(i, m){
			cin >> root[i];
			root[i] *= polar((R)1, (R)1);
		}
		pin[0] = root[0];
		REPS(i, n){
			cin >> pin[i];
			pin[i] *= polar((R)1, (R)1);
		}
		sort(pin.begin()+1, pin.end());
		pin.push_back(root.back());
		vector<int> st;
		st.push_back(0);
		REP(i, m-1){
			S s(root[i], root[i+1]);
			vi isc = path(s, pin);
			FOR(it, isc){
				if(st.back() == *it) st.pop_back();
				else st.push_back(*it);
			}
		}
		st.push_back(n+1);
		
		vector<R> dp(st.size(), INF);
		vi prev(st.size());
		dp[0] = .0;
		int save = 0;
		REP(i, st.size()){
			if(i && st[i] == -st[i-1]){
				save = i;
				dp[i] = dp[i-1];
				prev[i] = prev[i-1];
				continue;
			}
			for(int j=save;j<i;j++){
				S r(pin[abs(st[j])], pin[abs(st[i])]);
				vi pt = path(r, pin);
				if([&](){
					for(int k=1;k<=pt.size()&&j+k<i;k++) if(pt[k-1] != st[j+k]) return 0;
					return 1;
				}()){
					if(chmin(dp[i], dp[j] + abs(r.dir()))){
						prev[i] = j;
					}
				}
			}
		}
		printf("%.10f\n", (double)dp.back());
	}
	return 0;
}
accuracy: 1
time_ms: 4590
memory_kb: 1380
final_rank: 12

code_snippet: #include <algorithm>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <limits>
#include <vector>
namespace lc {
static const double EPS = 1e-9;
}
namespace lc {
struct Point {
	double x;
	double y;
	explicit Point(const double &x = 0.0, const double &y = 0.0) :
		x(x), y(y)
	{ }
	Point operator+(const Point &p) const { return Point(x + p.x, y + p.y); }
	Point &operator+=(const Point &p){ return *this = *this + p; }
	Point operator-(const Point &p) const { return Point(x - p.x, y - p.y); }
	Point operator*(double s) const { return Point(x * s, y * s); }
	bool operator==(const Point &p) const { return x == p.x && y == p.y; }
	bool operator<(const Point &p) const {
		return (x == p.x) ? (y < p.y) : (x < p.x);
	}
	double abs() const { return sqrt(x * x + y * y); }
	double norm() const { return x * x + y * y; }
};
inline Point operator*(double s, const Point &p){ return p * s; }
inline double cross(const Point &a, const Point &b){
	return a.x * b.y - a.y * b.x;
}
inline double dot(const Point &a, const Point &b){
	return a.x * b.x + a.y * b.y;
}
inline int ccw(const Point &a, const Point &b, const Point &c){
	Point d = b - a, e = c - a;
	if(cross(d, e) > 0.0){ return 1; }
	if(cross(d, e) < 0.0){ return -1; }
	if(dot(d, e) < 0.0){ return 2; }
	if(d.abs() < e.abs()){ return -2; }
	return 0;
}
}
namespace lc {
struct Line {
	Point a;
	Point b;
	explicit Line(const Point &a = Point(), const Point &b = Point()) :
		a(a), b(b)
	{ }
	Point projection(const Point &p) const {
		double t = dot(p - a, b - a) / (b - a).norm();
		return a + t * (b - a);
	}
};
}
namespace lc {
class Polygon {
private:
	std::vector<Point> m_points;
public:
	Polygon() : m_points() { }
	explicit Polygon(size_t s, const Point &p = Point())
		: m_points(s, p)
	{ }
	template <typename Iterator>
	explicit Polygon(Iterator begin, Iterator end)
		: m_points(begin, end)
	{ }
	explicit Polygon(std::initializer_list<Point> init)
		: m_points(init)
	{ }
	const Point &operator[](int i) const { return m_points[i]; }
	Point &operator[](int i){ return m_points[i]; }
	int size() const { return static_cast<int>(m_points.size()); }
	int contains(const Point &p) const {
		int result = -1;
		for(int i = 0; i < size(); ++i){
			Point a = m_points[i] - p;
			Point b = m_points[(i + 1) % size()] - p;
			if(a.y > b.y){ std::swap(a, b); }
			if(a.y <= 0.0 && b.y > 0.0 && cross(a, b) < 0.0){
				result = -result;
			}
			if(cross(a, b) == 0.0 && dot(a, b) <= 0.0){ return 0; }
		}
		return result;
	}
};
}
namespace lc {
inline Polygon convex_hull(const std::vector<Point> &points){
	const int n = points.size();
	std::vector<Point> ps(points);
	std::sort(ps.begin(), ps.end());
	std::vector<Point> ch(2 * n);
	int k = 0;
	for(int i = 0; i < n; ch[k++] = ps[i++]){
		while(k >= 2 && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0){ --k; }
	}
	for(int i = n - 2, t = k + 1; i >= 0; ch[k++] = ps[i--]){
		while(k >= t && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0){ --k; }
	}
	ch.resize(k - 1);
	return Polygon(ch.begin(), ch.end());
}
}
namespace lc {
class Visualizer {
private:
	double m_scale;
	double m_offset_x;
	double m_offset_y;
public:
	explicit Visualizer(
		double scale = 1.0, double offset_x = 0.0, double offset_y = 0.0)
		: m_scale(scale)
		, m_offset_x(offset_x)
		, m_offset_y(offset_y)
	{ }
};
}
using namespace std;
static const double EPS = lc::EPS;
static const lc::Point DIR_TABLE[4] = {
	lc::Point(1.0, 0.0),
	lc::Point(0.0, 1.0),
	lc::Point(-1.0, 0.0),
	lc::Point(0.0, -1.0)
};
int main(){
	ios_base::sync_with_stdio(false);
	cout << setiosflags(ios::fixed) << setprecision(10);
	lc::Visualizer vis(1.0, 0.0, 0.0);
	while(true){
		int m, n;
		cin >> m >> n;
		if(m == 0 && n == 0){ break; }
		vector<lc::Point> segments(m), polls(n * 4);
		for(int i = 0; i < m; ++i){ cin >> segments[i].x >> segments[i].y; }
		for(int i = 0; i < n; ++i){
			double x, y;
			cin >> x >> y;
			polls[i * 4 + 0] = lc::Point(x, y) + DIR_TABLE[0] * 10.0 * EPS;
			polls[i * 4 + 1] = lc::Point(x, y) + DIR_TABLE[1] * 10.0 * EPS;
			polls[i * 4 + 2] = lc::Point(x, y) + DIR_TABLE[2] * 10.0 * EPS;
			polls[i * 4 + 3] = lc::Point(x, y) + DIR_TABLE[3] * 10.0 * EPS;
		}
		while(true){
			bool modified = false;
			segments.erase(unique(
				segments.begin(), segments.end()), segments.end());
			vector<lc::Point> next;
			next.clear();
			for(size_t i = 0; i < segments.size(); ++i){
				next.push_back(segments[i]);
				if(i + 2 >= segments.size()){ continue; }
				if((segments[i + 2] - segments[i]).abs() < 2.0 * EPS){ continue; }
				lc::Polygon tri({
					segments[i], segments[i + 1], segments[i + 2]
				});
				for(size_t j = 0; j < polls.size(); ++j){
					const auto &p = polls[j];
					if(tri[1] == p){ tri[1] += DIR_TABLE[j % 4] * EPS; }
				}
				vector<lc::Point> pts({ segments[i], segments[i + 2] });
				for(size_t j = 0; j < polls.size(); ++j){
					const auto &p = polls[j];
					const int contains = tri.contains(p);
					if(contains > 0){
						pts.push_back(p);
					}else if(contains == 0){
						const auto &dir = DIR_TABLE[j % 4];
						const auto proj = lc::Line(
							segments[i], segments[i + 2]).projection(p);
						if(lc::dot(proj - p, dir) < 0.0){ pts.push_back(p); }
					}
				}
				const lc::Polygon conv = convex_hull(pts);
				int locs[3] = { -1, -1, -1 };
				for(int j = 0; j < conv.size(); ++j){
					for(int k = 0; k < 3; ++k){
						if(segments[i + k] == conv[j]){ locs[k] = j; }
					}
				}
				if(locs[1] < 0){
					const int t = conv.size();
					const int d = ((locs[0] + 1) % t == locs[2]) ? -1 : 1;
					for(int j = locs[0]; j != locs[2]; j = (j + d + t) % t){
						next.push_back(conv[j]);
					}
					modified = true;
					for(size_t j = i + 2; j < segments.size(); ++j){
						next.push_back(segments[j]);
					}
					break;
				}else{
					next.push_back(segments[i]);
				}
			}
			if(!modified){ break; }
			segments.swap(next);
		}
		double answer = 0.0;
		for(size_t i = 0; i + 1 < segments.size(); ++i){
			answer += (segments[i + 1] - segments[i]).abs();
		}
		cout << answer << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 1530
memory_kb: 1352
final_rank: 8