Problem p00931 (C++) — buggy submission, verdict: Runtime Error

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

// #define dump(n) cout<<"# "<<#n<<'='<<(n)<<endl
#define dump(n)                                                                \\
  cout << "\\e[0;32mL" << setw(3) << __LINE__ << ":\\e[0m " << #n << '=' << (n)  \\
       << endl
#define repi(i, a, b) for (int i = int(a); i < int(b); i++)
#define peri(i, a, b) for (int i = int(b); i-- > int(a);)
#define rep(i, n) repi(i, 0, n)
#define per(i, n) peri(i, 0, n)
#define all(c) begin(c), end(c)
#define mp make_pair
#define mt make_tuple

typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<double> vd;
typedef vector<vd> vvd;
typedef vector<string> vs;

const int INF = 1e9;
const int MOD = 1e9 + 7;
const double EPS = 1e-9;
const double PI = acos(-1);

template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p) {
  return os << '(' << p.first << ',' << p.second << ')';
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &a) {
  os << '[';
  rep(i, a.size()) os << (i ? " " : "") << a[i];
  return os << ']';
}

struct Point {
  double x, y;
  Point() {}
  Point(double x, double y) : x(x), y(y) {}
  Point &operator+=(Point p) {
    x += p.x, y += p.y;
    return *this;
  }
  Point &operator-=(Point p) {
    x -= p.x, y -= p.y;
    return *this;
  }
  Point &operator*=(double c) {
    x *= c, y *= c;
    return *this;
  }
  Point &operator/=(double c) {
    x /= c, y /= c;
    return *this;
  }
};
Point operator+(Point a, Point b) { return a += b; }
Point operator-(Point a, Point b) { return a -= b; }
Point operator*(Point a, double c) { return a *= c; }
Point operator*(double c, Point a) { return a *= c; }
Point operator/(Point a, double c) { return a /= c; }
bool operator==(Point a, Point b) {
  return abs(a.x - b.x) < EPS && abs(a.y - b.y) < EPS;
}
bool operator!=(Point a, Point b) { return !(a == b); }

struct Line {
  Point pos, dir;
  Line() {}
  Line(Point p, Point d) : pos(p), dir(d) {}
  Line(double x, double y, double u, double v) : pos(x, y), dir(u, v) {}
};

struct Segment {
  Point pos, dir;
  Segment() {}
  Segment(Point p, Point d) : pos(p), dir(d) {}
  Segment(double x, double y, double u, double v) : pos(x, y), dir(u, v) {}
  explicit Segment(Line l) : pos(l.pos), dir(l.dir) {}
  explicit operator Line() const { return Line(pos, dir); }
};

struct Circle {
  Point center;
  double radius;
  Circle() {}
  Circle(Point c, double r) : center(c), radius(r) {}
  Circle(double x, double y, double r) : center(x, y), radius(r) {}
};
bool operator==(Circle a, Circle b) {
  return a.center == b.center && abs(a.radius - b.radius) < EPS;
}
bool operator!=(Circle a, Circle b) { return !(a == b); }

ostream &operator<<(ostream &os, const Point &p) {
  return os << '(' << p.x << ',' << p.y << ')';
}
ostream &operator<<(ostream &os, const Line &l) {
  return os << '(' << l.pos << ',' << l.dir << ')';
}
ostream &operator<<(ostream &os, const Segment &s) {
  return os << '(' << s.pos << ',' << s.dir << ')';
}
ostream &operator<<(ostream &os, const Circle &c) {
  return os << '(' << c.center.x << ',' << c.center.y << ',' << c.radius << ')';
}

int Signum(double x) { return x < -EPS ? -1 : x > EPS ? 1 : 0; }

double Abs(Point p) { return sqrt(p.x * p.x + p.y * p.y); }
double Abs2(Point p) { return p.x * p.x + p.y * p.y; }
double Arg(Point p) { return atan2(p.y, p.x); }
double Dot(Point a, Point b) { return a.x * b.x + a.y * b.y; }
double Cross(Point a, Point b) { return a.x * b.y - a.y * b.x; }
Point Rot(Point p, double t) {
  return Point(cos(t) * p.x - sin(t) * p.y, sin(t) * p.x + cos(t) * p.y);
}

bool Orthogonal(Line a, Line b) { return abs(Dot(a.dir, b.dir)) < EPS; }
bool Parallel(Line a, Line b) { return abs(Cross(a.dir, b.dir)) < EPS; }
Point Proj(Line l, Point p) {
  Point a = p - l.pos, b = l.dir;
  return l.pos + Dot(a, b) / Abs2(b) * b;
}

int CCW(Point a, Point b, Point c) {
  b -= a, c -= a;
  if (int sign = Signum(Cross(b, c)))
    return sign; // 1:ccw,-1:cw
  if (Dot(b, c) < -EPS)
    return -2; // c-a-b
  if (Abs2(b) < Abs2(c) - EPS)
    return 2; // a-b-c
  return 0;   // a-c-b (inclusive)
}

vector<Line> Intangent(Circle c1, Circle c2) {
  double r1 = c1.radius, r2 = c2.radius;
  double d = Abs(c1.center - c2.center);
  vector<Line> res;
  if (d > r1 + r2 + EPS) {
    double t = acos((r1 + r2) / d);
    rep(i, 2) {
      Point p1 =
          c1.center + Rot(r1 / d * (c2.center - c1.center), (i ? 1 : -1) * t);
      Point p2 =
          c2.center + Rot(r2 / d * (c1.center - c2.center), (i ? 1 : -1) * t);
      res.push_back(Line(p1, p2 - p1));
    }
  } else if (d > r1 + r2 - EPS) {
    Point p = c1.center + r1 / d * (c2.center - c1.center);
    res.push_back(Line(p, Rot(p - c1.center, PI / 2)));
  }
  return res;
}
vector<Line> Extangent(Circle c1, Circle c2) {
  double r1 = c1.radius, r2 = c2.radius;
  double d = Abs(c1.center - c2.center);
  vector<Line> res;
  if (d > abs(r2 - r1) + EPS) {
    double t = acos((r1 - r2) / d);
    rep(i, 2) {
      Point p1 =
          c1.center + Rot(r1 / d * (c2.center - c1.center), (i ? 1 : -1) * t);
      Point p2 =
          c2.center + Rot(r2 / d * (c2.center - c1.center), (i ? 1 : -1) * t);
      res.push_back(Line(p1, p2 - p1));
    }
  } else if (d > abs(r2 - r1) - EPS) {
    Point p = c1.center + r1 / d * (c2.center - c1.center);
    res.push_back(Line(p, Rot(p - c1.center, PI / 2)));
  }
  return res;
}

vector<Point> TangentPoint(Circle c1, Circle c2) {
  vector<Point> res;
  vector<Line> in = Intangent(c1, c2);
  for (Line l : in) {
    res.push_back(Proj(l, c1.center));
    res.push_back(Proj(l, c2.center));
  }
  vector<Line> ex = Extangent(c1, c2);
  for (Line l : ex) {
    res.push_back(Proj(l, c1.center));
    res.push_back(Proj(l, c2.center));
  }
  return res;
}

double DistLP(Line l, Point p) { return Abs(Proj(l, p) - p); }
double DistSP(Segment s, Point p) {
  int ccw = CCW(s.pos, s.pos + s.dir, Proj(Line(s), p));
  if (ccw == -2)
    return Abs(s.pos - p);
  if (ccw == 2)
    return Abs(s.pos + s.dir - p);
  return DistLP(Line(s), p);
}

pair<Point, Point> InterPointCC(Circle c1, Circle c2) {
  Point p1 = c1.center, p2 = c2.center;
  double r1 = c1.radius, r2 = c2.radius;
  double d = Abs(p1 - p2);
  double a = (d * d + r1 * r1 - r2 * r2) / (2 * d);
  double s = sqrt(r1 * r1 - a * a);
  return mp(p1 + a / d * (p2 - p1) + s * Rot((p2 - p1) / d, PI / 2),
            p1 + a / d * (p2 - p1) - s * Rot((p2 - p1) / d, PI / 2));
}

// xがa~b(反時計周り)の区間にあるかどうか．a,b,xはラジアン．
bool InArc(double a, double b, double x) {
  if (a < b)
    return a < x && x < b;
  else
    return a < x || x < b;
}
double ArcLength(double r, double a, double b) {
  if (a < b)
    return r * (b - a);
  else
    return r * (b - a + 2 * PI);
}

vector<Line> Tangent(Circle c, Point p) { return Intangent(c, Circle(p, 0)); }

struct Edge {
  int src, dst;
  double weight;
  Edge() {}
  Edge(int s, int d, double w) : src(s), dst(d), weight(w) {}
};
bool operator<(Edge a, Edge b) { return a.weight < b.weight; }
bool operator>(Edge a, Edge b) { return a.weight > b.weight; }
typedef vector<vector<Edge>> Graph;

void Dijkstra(const Graph &g, int v, vd &dist) {
  priority_queue<Edge, vector<Edge>, greater<Edge>> pq;
  pq.emplace(-1, v, 0);
  while (pq.size()) {
    Edge cur = pq.top();
    pq.pop();
    if (dist[cur.dst] != INF)
      continue;
    dist[cur.dst] = cur.weight;
    for (Edge e : g[cur.dst])
      pq.emplace(e.src, e.dst, cur.weight + e.weight);
  }
}

int main() {
  const double R = 100;

  for (int n; cin >> n && n;) {
    Point start(0, 0), goal;
    cin >> goal.x >> goal.y;
    vector<Point> poles(n); // poles
    for (auto &p : poles)
      cin >> p.x >> p.y;

    vector<Circle> cs(n);
    rep(i, n) cs[i] = Circle(poles[i], R);

    // 始点・終点から円へ引いた接線の接点
    vector<pair<Point, int>> pairs; // (頂点，どの円の周上の点であるか)
    rep(i, n) {
      vector<Line> t = Extangent(cs[i], Circle(start, 0));
      for (Line l : t)
        pairs.emplace_back(Proj(l, cs[i].center), i);
    }
    rep(i, n) {
      vector<Line> t = Extangent(cs[i], Circle(goal, 0));
      for (Line l : t)
        pairs.emplace_back(Proj(l, cs[i].center), i);
    }

    // 円の共通接線の接点
    rep(i, n) repi(j, i + 1, n) {
      vector<Line> t = Intangent(cs[i], cs[j]);
      for (Line l : t) {
        pairs.emplace_back(Proj(l, cs[i].center), i);
        pairs.emplace_back(Proj(l, cs[j].center), j);
      }
      t = Extangent(cs[i], cs[j]);
      for (Line l : t) {
        pairs.emplace_back(Proj(l, cs[i].center), i);
        pairs.emplace_back(Proj(l, cs[j].center), j);
      }
    }

    // 無駄な頂点を消しつつpairをばらす
    vector<Point> ps;
    vi is;
    for (auto tmp : pairs) {
      Point p;
      int i;
      tie(p, i) = tmp;
      bool in = false;
      for (Circle c : cs)
        in |= Abs(p - c.center) < R - EPS;
      if (!in) {
        ps.push_back(p);
        is.push_back(i);
      }
    }

    // dump(ps.size()); dump(ps);
    // puts("[DOT]");
    // printf("%f %f\\n%f %f\\n",start.x,start.y,goal.x,goal.y);
    // puts("[CIRCLE]");
    // for(Circle c:cs)
    //	printf("%f %f %f\\n",c.center.x,c.center.y,c.radius);
    // puts("[DOT]");
    // for(Point p:ps)
    //	printf("%f %f\\n",p.x,p.y);

    ps.push_back(start);
    is.push_back(-1);
    ps.push_back(goal);
    is.push_back(-2);

    Graph g(ps.size());
    rep(i, ps.size()) repi(j, i + 1, ps.size()) {
      if (is[i] == is[j]) { // 円周上をたどる
        Circle c1 = cs[is[i]];
        double a1 = Arg(ps[i] - c1.center), a2 = Arg(ps[j] - c1.center);
        rep(_, 2) {
          bool intersect = false;
          rep(k, n) {
            Circle c2 = cs[k];
            if (Abs(c2.center - c1.center) > 2 * R + EPS)
              continue;
            Point p1, p2;
            tie(p1, p2) = InterPointCC(c1, c2);
            intersect |= InArc(a1, a2, Arg(p1 - c1.center));
            intersect |= InArc(a1, a2, Arg(p2 - c1.center));
          }
          if (!intersect) {
            g[i].emplace_back(i, j, ArcLength(R, a1, a2));
            g[j].emplace_back(j, i, ArcLength(R, a1, a2));
          }
          swap(a1, a2);
        }
      } else {
        Segment s(ps[i], ps[j] - ps[i]);
        bool intersect = false;
        rep(k, n) intersect |= DistSP(s, cs[k].center) < R - EPS;
        if (!intersect) {
          g[i].emplace_back(i, j, Abs(s.dir));
          g[j].emplace_back(j, i, Abs(s.dir));
        }
      }
    }

    // puts("[LINE_SEGMENT]");
    // rep(i,g.size()) for(Edge e:g[i]) if(e.src<e.dst){
    //	Point p=ps[e.src],q=ps[e.dst];
    //	printf("%f %f %f %f\\n",p.x,p.y,q.x,q.y);
    // }

    vd dist(ps.size(), INF);
    Dijkstra(g, dist.size() - 2, dist);
    if (dist.back() == INF)
      puts("0.0");
    else
      printf("%.10f\\n", dist.back());
  }
}

Error: WA

Fixed submission:

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

// #define dump(n) cout<<"# "<<#n<<'='<<(n)<<endl
#define dump(n)                                                                \\
  cout << "\\e[0;32mL" << setw(3) << __LINE__ << ":\\e[0m " << #n << '=' << (n)  \\
       << endl
#define repi(i, a, b) for (int i = int(a); i < int(b); i++)
#define peri(i, a, b) for (int i = int(b); i-- > int(a);)
#define rep(i, n) repi(i, 0, n)
#define per(i, n) peri(i, 0, n)
#define all(c) begin(c), end(c)
#define mp make_pair
#define mt make_tuple

typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<double> vd;
typedef vector<vd> vvd;
typedef vector<string> vs;

const int INF = 1e9;
const int MOD = 1e9 + 7;
const double EPS = 1e-9;
const double PI = acos(-1);

template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p) {
  return os << '(' << p.first << ',' << p.second << ')';
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &a) {
  os << '[';
  rep(i, a.size()) os << (i ? " " : "") << a[i];
  return os << ']';
}

struct Point {
  double x, y;
  Point() {}
  Point(double x, double y) : x(x), y(y) {}
  Point &operator+=(Point p) {
    x += p.x, y += p.y;
    return *this;
  }
  Point &operator-=(Point p) {
    x -= p.x, y -= p.y;
    return *this;
  }
  Point &operator*=(double c) {
    x *= c, y *= c;
    return *this;
  }
  Point &operator/=(double c) {
    x /= c, y /= c;
    return *this;
  }
};
Point operator+(Point a, Point b) { return a += b; }
Point operator-(Point a, Point b) { return a -= b; }
Point operator*(Point a, double c) { return a *= c; }
Point operator*(double c, Point a) { return a *= c; }
Point operator/(Point a, double c) { return a /= c; }
bool operator==(Point a, Point b) {
  return abs(a.x - b.x) < EPS && abs(a.y - b.y) < EPS;
}
bool operator!=(Point a, Point b) { return !(a == b); }

struct Line {
  Point pos, dir;
  Line() {}
  Line(Point p, Point d) : pos(p), dir(d) {}
  Line(double x, double y, double u, double v) : pos(x, y), dir(u, v) {}
};

struct Segment {
  Point pos, dir;
  Segment() {}
  Segment(Point p, Point d) : pos(p), dir(d) {}
  Segment(double x, double y, double u, double v) : pos(x, y), dir(u, v) {}
  explicit Segment(Line l) : pos(l.pos), dir(l.dir) {}
  explicit operator Line() const { return Line(pos, dir); }
};

struct Circle {
  Point center;
  double radius;
  Circle() {}
  Circle(Point c, double r) : center(c), radius(r) {}
  Circle(double x, double y, double r) : center(x, y), radius(r) {}
};
bool operator==(Circle a, Circle b) {
  return a.center == b.center && abs(a.radius - b.radius) < EPS;
}
bool operator!=(Circle a, Circle b) { return !(a == b); }

ostream &operator<<(ostream &os, const Point &p) {
  return os << '(' << p.x << ',' << p.y << ')';
}
ostream &operator<<(ostream &os, const Line &l) {
  return os << '(' << l.pos << ',' << l.dir << ')';
}
ostream &operator<<(ostream &os, const Segment &s) {
  return os << '(' << s.pos << ',' << s.dir << ')';
}
ostream &operator<<(ostream &os, const Circle &c) {
  return os << '(' << c.center.x << ',' << c.center.y << ',' << c.radius << ')';
}

int Signum(double x) { return x < -EPS ? -1 : x > EPS ? 1 : 0; }

double Abs(Point p) { return sqrt(p.x * p.x + p.y * p.y); }
double Abs2(Point p) { return p.x * p.x + p.y * p.y; }
double Arg(Point p) { return atan2(p.y, p.x); }
double Dot(Point a, Point b) { return a.x * b.x + a.y * b.y; }
double Cross(Point a, Point b) { return a.x * b.y - a.y * b.x; }
Point Rot(Point p, double t) {
  return Point(cos(t) * p.x - sin(t) * p.y, sin(t) * p.x + cos(t) * p.y);
}

bool Orthogonal(Line a, Line b) { return abs(Dot(a.dir, b.dir)) < EPS; }
bool Parallel(Line a, Line b) { return abs(Cross(a.dir, b.dir)) < EPS; }
Point Proj(Line l, Point p) {
  Point a = p - l.pos, b = l.dir;
  return l.pos + Dot(a, b) / Abs2(b) * b;
}

int CCW(Point a, Point b, Point c) {
  b -= a, c -= a;
  if (int sign = Signum(Cross(b, c)))
    return sign; // 1:ccw,-1:cw
  if (Dot(b, c) < -EPS)
    return -2; // c-a-b
  if (Abs2(b) < Abs2(c) - EPS)
    return 2; // a-b-c
  return 0;   // a-c-b (inclusive)
}

vector<Line> Intangent(Circle c1, Circle c2) {
  double r1 = c1.radius, r2 = c2.radius;
  double d = Abs(c1.center - c2.center);
  vector<Line> res;
  if (d > r1 + r2 + EPS) {
    double t = acos((r1 + r2) / d);
    rep(i, 2) {
      Point p1 =
          c1.center + Rot(r1 / d * (c2.center - c1.center), (i ? 1 : -1) * t);
      Point p2 =
          c2.center + Rot(r2 / d * (c1.center - c2.center), (i ? 1 : -1) * t);
      res.push_back(Line(p1, p2 - p1));
    }
  } else if (d > r1 + r2 - EPS) {
    Point p = c1.center + r1 / d * (c2.center - c1.center);
    res.push_back(Line(p, Rot(p - c1.center, PI / 2)));
  }
  return res;
}
vector<Line> Extangent(Circle c1, Circle c2) {
  double r1 = c1.radius, r2 = c2.radius;
  double d = Abs(c1.center - c2.center);
  vector<Line> res;
  if (d > abs(r2 - r1) + EPS) {
    double t = acos((r1 - r2) / d);
    rep(i, 2) {
      Point p1 =
          c1.center + Rot(r1 / d * (c2.center - c1.center), (i ? 1 : -1) * t);
      Point p2 =
          c2.center + Rot(r2 / d * (c2.center - c1.center), (i ? 1 : -1) * t);
      res.push_back(Line(p1, p2 - p1));
    }
  } else if (d > abs(r2 - r1) - EPS) {
    Point p = c1.center + r1 / d * (c2.center - c1.center);
    res.push_back(Line(p, Rot(p - c1.center, PI / 2)));
  }
  return res;
}

vector<Point> TangentPoint(Circle c1, Circle c2) {
  vector<Point> res;
  vector<Line> in = Intangent(c1, c2);
  for (Line l : in) {
    res.push_back(Proj(l, c1.center));
    res.push_back(Proj(l, c2.center));
  }
  vector<Line> ex = Extangent(c1, c2);
  for (Line l : ex) {
    res.push_back(Proj(l, c1.center));
    res.push_back(Proj(l, c2.center));
  }
  return res;
}

double DistLP(Line l, Point p) { return Abs(Proj(l, p) - p); }
double DistSP(Segment s, Point p) {
  int ccw = CCW(s.pos, s.pos + s.dir, Proj(Line(s), p));
  if (ccw == -2)
    return Abs(s.pos - p);
  if (ccw == 2)
    return Abs(s.pos + s.dir - p);
  return DistLP(Line(s), p);
}

pair<Point, Point> InterPointCC(Circle c1, Circle c2) {
  Point p1 = c1.center, p2 = c2.center;
  double r1 = c1.radius, r2 = c2.radius;
  double d = Abs(p1 - p2);
  double a = (d * d + r1 * r1 - r2 * r2) / (2 * d);
  double s = sqrt(r1 * r1 - a * a);
  return mp(p1 + a / d * (p2 - p1) + s * Rot((p2 - p1) / d, PI / 2),
            p1 + a / d * (p2 - p1) - s * Rot((p2 - p1) / d, PI / 2));
}

// xがa~b(反時計周り)の区間にあるかどうか．a,b,xはラジアン．
bool InArc(double a, double b, double x) {
  if (a < b)
    return a < x && x < b;
  else
    return a < x || x < b;
}
double ArcLength(double r, double a, double b) {
  if (a < b)
    return r * (b - a);
  else
    return r * (b - a + 2 * PI);
}

vector<Line> Tangent(Circle c, Point p) { return Intangent(c, Circle(p, 0)); }

struct Edge {
  int src, dst;
  double weight;
  Edge() {}
  Edge(int s, int d, double w) : src(s), dst(d), weight(w) {}
};
bool operator<(Edge a, Edge b) { return a.weight < b.weight; }
bool operator>(Edge a, Edge b) { return a.weight > b.weight; }
typedef vector<vector<Edge>> Graph;

void Dijkstra(const Graph &g, int v, vd &dist) {
  priority_queue<Edge, vector<Edge>, greater<Edge>> pq;
  pq.emplace(-1, v, 0);
  while (pq.size()) {
    Edge cur = pq.top();
    pq.pop();
    if (dist[cur.dst] != INF)
      continue;
    dist[cur.dst] = cur.weight;
    for (Edge e : g[cur.dst])
      pq.emplace(e.src, e.dst, cur.weight + e.weight);
  }
}

int main() {
  const double R = 100;

  for (int n; cin >> n && n;) {
    Point start(0, 0), goal;
    cin >> goal.x >> goal.y;
    vector<Point> poles(n); // poles
    for (auto &p : poles)
      cin >> p.x >> p.y;

    vector<Circle> cs(n);
    rep(i, n) cs[i] = Circle(poles[i], R);

    // 始点・終点から円へ引いた接線の接点
    vector<Point> ps;
    for (Circle c : cs) {
      vector<Line> t = Extangent(c, Circle(start, 0));
      for (Line l : t)
        ps.push_back(Proj(l, c.center));
    }
    for (Circle c : cs) {
      vector<Line> t = Extangent(c, Circle(goal, 0));
      for (Line l : t)
        ps.push_back(Proj(l, c.center));
    }

    // 円の共通接線の接点
    rep(i, n) repi(j, i + 1, n) {
      vector<Line> t = Intangent(cs[i], cs[j]);
      for (Line l : t) {
        ps.push_back(Proj(l, cs[i].center));
        ps.push_back(Proj(l, cs[j].center));
      }
      t = Extangent(cs[i], cs[j]);
      for (Line l : t) {
        ps.push_back(Proj(l, cs[i].center));
        ps.push_back(Proj(l, cs[j].center));
      }
    }

    // 無駄な頂点を消す
    {
      vector<Point> qs;
      for (Point p : ps) {
        bool in = false;
        for (Circle c : cs)
          in |= Abs(p - c.center) < R - EPS;
        if (!in)
          qs.push_back(p);
      }
      swap(ps, qs);
    }

    // dump(ps.size()); dump(ps);
    // puts("[DOT]");
    // printf("%f %f\\n%f %f\\n",start.x,start.y,goal.x,goal.y);
    // puts("[CIRCLE]");
    // for(Circle c:cs)
    //	printf("%f %f %f\\n",c.center.x,c.center.y,c.radius);
    // puts("[DOT]");
    // for(Point p:ps)
    //	printf("%f %f\\n",p.x,p.y);

    // ps[i]はis[i]番目の円の周上にある
    vi is;
    for (Point p : ps)
      rep(i, n) if (abs(Abs(p - cs[i].center) - R) < EPS) is.push_back(i);

    ps.push_back(start);
    is.push_back(-1);
    ps.push_back(goal);
    is.push_back(-2);

    assert(ps.size() == is.size());

    Graph g(ps.size());
    rep(i, ps.size()) repi(j, i + 1, ps.size()) {
      if (is[i] == is[j]) { // 円周上をたどる
        Circle c1 = cs[is[i]];
        double a1 = Arg(ps[i] - c1.center), a2 = Arg(ps[j] - c1.center);
        rep(_, 2) {
          bool intersect = false;
          rep(k, n) {
            Circle c2 = cs[k];
            if (Abs(c2.center - c1.center) > 2 * R + EPS)
              continue;
            Point p1, p2;
            tie(p1, p2) = InterPointCC(c1, c2);
            intersect |= InArc(a1, a2, Arg(p1 - c1.center));
            intersect |= InArc(a1, a2, Arg(p2 - c1.center));
          }
          if (!intersect) {
            g[i].emplace_back(i, j, ArcLength(R, a1, a2));
            g[j].emplace_back(j, i, ArcLength(R, a1, a2));
          }
          swap(a1, a2);
        }
      } else {
        Segment s(ps[i], ps[j] - ps[i]);
        bool intersect = false;
        rep(k, n) intersect |= DistSP(s, cs[k].center) < R - EPS;
        if (!intersect) {
          g[i].emplace_back(i, j, Abs(s.dir));
          g[j].emplace_back(j, i, Abs(s.dir));
        }
      }
    }

    // puts("[LINE_SEGMENT]");
    // rep(i,g.size()) for(Edge e:g[i]) if(e.src<e.dst){
    //	Point p=ps[e.src],q=ps[e.dst];
    //	printf("%f %f %f %f\\n",p.x,p.y,q.x,q.y);
    // }

    vd dist(ps.size(), INF);
    Dijkstra(g, dist.size() - 2, dist);
    if (dist.back() == INF)
      puts("0.0");
    else
      printf("%.10f\\n", dist.back());
  }
}