import static java.lang.Math.*; import static java.util.Arrays.*; import java.util.*; public class Main { Scanner sc = new Scanner(System.in); double INF = Double.POSITIVE_INFINITY; P[] ds = {new P(-1, 0), new P(0, -1), new P(0, 1), new P(1, 0)}; int n; P[] cs; double[] rs; void run() { n = sc.nextInt(); V s = new V(new P(sc.nextDouble(), sc.nextDouble())); cs = new P[n]; rs = new double[n]; for (int i = 0; i < n; i++) { cs[i] = new P(sc.nextDouble(), sc.nextDouble()); rs[i] = sc.nextDouble(); } int[] hs = new int[n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { for (int k = 0; k < n; k++) if (rs[j] < rs[k] && cs[j].sub(cs[k]).abs() < rs[k]) { hs[j] = max(hs[j], hs[k] + 1); } } } V[][] vs4 = new V[n][4]; for (int i = 0; i < n; i++) for (int j = 0; j < 4; j++) vs4[i][j] = new V(cs[i].add(ds[j].mul(rs[i]))); ArrayList[] vs = new ArrayList[n]; for (int i = 0; i < n; i++) vs[i] = new ArrayList(); for (int i = 0; i < n; i++) { // 二円の共通接線 for (int j = 0; j < i; j++) { for (P[] ps : tanCC(cs[i], rs[i], cs[j], rs[j])) { V v = new V(ps[0]), u = new V(ps[1]); int can = can(v.p, u.p); if (can > 0) { vs[i].add(v); vs[j].add(u); if ((can & 1) != 0) v.add(new E(u, v.p.sub(u.p).abs())); if ((can & 2) != 0) u.add(new E(v, v.p.sub(u.p).abs())); } } } // 四隅からの接線 for (int j = 0; j < 4; j++) { V v = vs4[i][j]; vs[i].add(v); for (int k = 0; k < n; k++) if (i != k) { for (P p : tanCP(cs[k], rs[k], v.p)) { V u = new V(p); int can = can(v.p, u.p); if (can > 0) { vs[k].add(u); if ((can & 1) != 0) v.add(new E(u, v.p.sub(u.p).abs())); if ((can & 2) != 0) u.add(new E(v, v.p.sub(u.p).abs())); } } } } // 四隅同士 for (int j = 0; j < 4; j++) { for (int i2 = 0; i2 < i; i2++) if (i != i2) { for (int j2 = 0; j2 < 4; j2++) { int can = can(vs4[i][j].p, vs4[i2][j2].p); if ((can & 1) != 0) vs4[i][j].add(new E(vs4[i2][j2], vs4[i][j].p.sub(vs4[i2][j2].p).abs())); if ((can & 2) != 0) vs4[i2][j2].add(new E(vs4[i][j], vs4[i][j].p.sub(vs4[i2][j2].p).abs())); } } } // 始点から四隅 for (int j = 0; j < 4; j++) { if ((can(s.p, vs4[i][j].p) & 1) != 0) s.add(new E(vs4[i][j], s.p.sub(vs4[i][j].p).abs())); } // 始点からの接線 for (P p : tanCP(cs[i], rs[i], s.p)) { if ((can(s.p, p) & 1) != 0) { V v = new V(p); vs[i].add(v); s.add(new E(v, s.p.sub(p).abs())); } } } // 円周 for (int i = 0; i < n; i++) { for (V v : vs[i]) v.rad = v.p.sub(cs[i]).rad(); Collections.sort(vs[i]); for (int j = 0; j < vs[i].size(); j++) { V v = vs[i].get(j), u = vs[i].get((j + 1) % vs[i].size()); double rad = u.rad - v.rad; if (rad < 0) rad += 2 * PI; v.add(new E(u, rs[i] * rad)); u.add(new E(v, rs[i] * rad)); } } dijkstra(s); double res = INF; int max = 0; for (int i = 0; i < n; i++) max = max(max, hs[i]); for (int i = 0; i < n; i++) if (hs[i] == max) { if (s.p.sub(cs[i]).abs() < rs[i]) res = 0; for (V v : vs4[i]) res = min(res, v.min); } System.out.printf("%.10f%n", res); } int can(P p1, P p2) { int can = 3; for (int i = 0; i < n; i++) if (crsCS(cs[i], rs[i], p1, p2)) { if (p1.sub(cs[i]).abs() > rs[i] + EPS) can &= ~1; if (p2.sub(cs[i]).abs() > rs[i] + EPS) can &= ~2; } return can; } void dijkstra(V s) { PriorityQueue que = new PriorityQueue(); s.min = 0; que.offer(new E(s, 0)); while (!que.isEmpty()) { V v = que.poll().to; if (v.fixed) continue; v.fixed = true; for (E e : v) if (!e.to.fixed) { if (e.to.min > v.min + e.cost) { e.to.min = v.min + e.cost; que.offer(new E(e.to, e.to.min)); } } } } class V extends ArrayList implements Comparable { double min = INF; boolean fixed; P p; double rad; V(P p) { this.p = p; } @Override public int compareTo(V o) { return Double.compare(rad, o.rad); } } class E implements Comparable { V to; double cost; E(V to, double cost) { this.to = to; this.cost = cost; } @Override public int compareTo(E o) { return Double.compare(cost, o.cost); } } double EPS = 1e-10; class P { double x, y; P(double x, double y) { this.x = x; this.y = y; } P add(P p) { return new P(x + p.x, y + p.y); } P sub(P p) { return new P(x - p.x, y - p.y); } P mul(double d) { return new P(x * d, y * d); } P div(double d) { return new P(x / d, y / d); } double dot(P p) { return x * p.x + y * p.y; } double det(P p) { return x * p.y - y * p.x; } double abs() { return sqrt(abs2()); } double abs2() { return x * x + y * y; } P rot90() { return new P(-y, x); } double rad() { return atan2(y, x); } } double disLP(P p1, P p2, P q) { return abs(p2.sub(p1).det(q.sub(p1))) / p2.sub(p1).abs(); } double disSP(P p1, P p2, P q) { if (p2.sub(p1).dot(q.sub(p1)) < EPS) return q.sub(p1).abs(); if (p1.sub(p2).dot(q.sub(p2)) < EPS) return q.sub(p2).abs(); return disLP(p1, p2, q); } boolean crsCS(P c, double r, P p1, P p2) { return disSP(p1, p2, c) < r - EPS && (r < c.sub(p1).abs() - EPS || r < c.sub(p2).abs() - EPS); } P[] tanCP(P c, double r, P p) { P v = p.sub(c); double d2 = v.abs2(); if (d2 - r * r < -EPS) return new P[0]; P q1 = c.add(v.mul(r * r / d2)); P q2 = v.rot90().mul(r * sqrt(max(0, d2 - r * r)) / d2); return new P[]{q1.sub(q2), q1.add(q2)}; } P[][] tanCC(P c1, double r1, P c2, double r2) { List list = new ArrayList(); if (abs(r1 - r2) < EPS) { P dir = c2.sub(c1); dir = dir.mul(r1 / dir.abs()).rot90(); list.add(new P[] {c1.add(dir), c2.add(dir)}); list.add(new P[] {c1.sub(dir), c2.sub(dir)}); } else { P p = c1.mul(-r2).add(c2.mul(r1)).div(r1 - r2); P[] ps = tanCP(c1, r1, p); P[] qs = tanCP(c2, r2, p); for (int i = 0; i < ps.length && i < qs.length; i++) { list.add(new P[] {ps[i], qs[i]}); } } P p = c1.mul(r2).add(c2.mul(r1)).div(r1 + r2); P[] ps = tanCP(c1, r1, p); P[] qs = tanCP(c2, r2, p); for (int i = 0; i < ps.length && i < qs.length; i++) { list.add(new P[] {ps[i], qs[i]}); } return list.toArray(new P[0][]); } public static void main(String[] args) { new Main().run(); } }