Problem:
Score : 600 points

Problem Statement

On the xy-plane, Snuke is going to travel from the point (x_s, y_s) to the point (x_t, y_t).
He can move in arbitrary directions with speed 1.
Here, we will consider him as a point without size.

There are N circular barriers deployed on the plane.
The center and the radius of the i-th barrier are (x_i, y_i) and r_i, respectively.
The barriers may overlap or contain each other.

A point on the plane is exposed to cosmic rays if the point is not within any of the barriers.

Snuke wants to avoid exposure to cosmic rays as much as possible during the travel.
Find the minimum possible duration of time he is exposed to cosmic rays during the travel.

Constraints

All input values are integers.

-10^9 ≤ x_s, y_s, x_t, y_t ≤ 10^9

(x_s, y_s) ≠ (x_t, y_t)

1≤N≤1,000

-10^9 ≤ x_i, y_i ≤ 10^9

1 ≤ r_i ≤ 10^9

Input

The input is given from Standard Input in the following format:

x_s y_s x_t y_t
N
x_1 y_1 r_1
x_2 y_2 r_2
:
x_N y_N r_N

Output

Print the minimum possible duration of time Snuke is exposed to cosmic rays during the travel.
The output is considered correct if the absolute or relative error is at most 10^{-9}.

Sample Input 1

-2 -2 2 2
1
0 0 1

Sample Output 1

3.6568542495

An optimal route is as follows:

Sample Input 2

-2 0 2 0
2
-1 0 2
1 0 2

Sample Output 2

0.0000000000

An optimal route is as follows:

Sample Input 3

4 -2 -2 4
3
0 0 2
4 0 1
0 4 1

Sample Output 3

4.0000000000

An optimal route is as follows:

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using static System.Math;
using System.Text;
using System.Threading;
using System.Globalization;
using System.Runtime.CompilerServices;
using Library;

namespace Program
{
    public static class ProblemA
    {
        static bool SAIKI = false;
        static public int numberOfRandomCases = 0;
        static public void MakeTestCase(List<string> _input, List<string> _output, ref Func<string[], bool> _outputChecker)
        {
        }
        static public void Solve()
        {
            var xs = NN;
            var ys = NN;
            var xt = NN;
            var yt = NN;
            var N = NN;
            var xyr = Repeat(0, N).Select(_ => new { x = NN, y = NN, r = NN }).ToArray();
            var path = Repeat(0, N + 2).Select(_ => new List<Tuple<long, double>>()).ToArray();
            for (var i = 0; i < N; i++)
            {
                for (var j = i + 1; j < N; j++)
                {
                    var p1 = new LIB_Geo2D.Vec(xyr[i].x, xyr[i].y);
                    var p2 = new LIB_Geo2D.Vec(xyr[j].x, xyr[j].y);
                    var dist = Sqrt(LIB_Geo2D.Distance(p1, p2)) - xyr[i].r - xyr[j].r;
                    if (dist < LIB_Geo2D.EPS) dist = 0;
                    path[i].Add(Tuple.Create((long)j, dist));
                    path[j].Add(Tuple.Create((long)i, dist));
                }
            }
            for (var j = 0; j < N; j++)
            {
                var p1 = new LIB_Geo2D.Vec(xs, ys);
                var p2 = new LIB_Geo2D.Vec(xyr[j].x, xyr[j].y);
                var dist = Sqrt(LIB_Geo2D.Distance(p1, p2)) - xyr[j].r;
                if (dist < LIB_Geo2D.EPS) dist = 0;
                path[N].Add(Tuple.Create((long)j, dist));
                path[j].Add(Tuple.Create((long)N, dist));
            }
            for (var j = 0; j < N; j++)
            {
                var p1 = new LIB_Geo2D.Vec(xt, yt);
                var p2 = new LIB_Geo2D.Vec(xyr[j].x, xyr[j].y);
                var dist = Sqrt(LIB_Geo2D.Distance(p1, p2)) - xyr[j].r;
                if (dist < LIB_Geo2D.EPS) dist = 0;
                path[N + 1].Add(Tuple.Create((long)j, dist));
                path[j].Add(Tuple.Create((long)N + 1, dist));
            }
            {
                var p1 = new LIB_Geo2D.Vec(xt, yt);
                var p2 = new LIB_Geo2D.Vec(xs, ys);
                var dist = Sqrt(LIB_Geo2D.Distance(p1, p2));
                if (dist < LIB_Geo2D.EPS) dist = 0;
                path[N + 1].Add(Tuple.Create((long)N, dist));
                path[N].Add(Tuple.Create((long)N + 1, dist));
            }
            {
                var nodeNum = N + 2;
                var start = N;
                var dist = Repeat(double.MaxValue / 4, nodeNum).ToArray();
                dist[start] = 0;
                var close = new bool[nodeNum];
                while (true)
                {
                    var minDist = double.MaxValue / 4; // !!!
                    var minVtx = -1;
                    for (var k = 0; k < nodeNum; k++)
                    {
                        if (!close[k])
                        {
                            if (minDist > dist[k]) // !!!
                            {
                                minDist = dist[k];
                                minVtx = k;
                            }
                        }
                    }
                    if (minVtx == -1) break;
                    close[minVtx] = true;
                    foreach (var item in path[minVtx])
                    {
                        var distTemp = dist[minVtx] + item.Item2; // !!!
                        if (dist[item.Item1] > distTemp) // !!!
                        {
                            dist[item.Item1] = distTemp;
                        }
                    }
                }
                Console.WriteLine(dist[N + 1]);
            }
        }
        class Printer : StreamWriter
        {
            public override IFormatProvider FormatProvider { get { return CultureInfo.InvariantCulture; } }
            public Printer(Stream stream) : base(stream, new UTF8Encoding(false, true)) { base.AutoFlush = false; }
            public Printer(Stream stream, Encoding encoding) : base(stream, encoding) { base.AutoFlush = false; }
        }
        static LIB_FastIO fastio = new LIB_FastIODebug();
        static public void Main(string[] args) { if (args.Length == 0) { fastio = new LIB_FastIO(); Console.SetOut(new Printer(Console.OpenStandardOutput())); } if (SAIKI) { var t = new Thread(Solve, 134217728); t.Start(); t.Join(); } else Solve(); Console.Out.Flush(); }
        static long NN => fastio.Long();
        static double ND => fastio.Double();
        static string NS => fastio.Scan();
        static long[] NNList(long N) => Repeat(0, N).Select(_ => NN).ToArray();
        static double[] NDList(long N) => Repeat(0, N).Select(_ => ND).ToArray();
        static string[] NSList(long N) => Repeat(0, N).Select(_ => NS).ToArray();
        static long Count<T>(this IEnumerable<T> x, Func<T, bool> pred) => Enumerable.Count(x, pred);
        static IEnumerable<T> Repeat<T>(T v, long n) => Enumerable.Repeat<T>(v, (int)n);
        static IEnumerable<int> Range(long s, long c) => Enumerable.Range((int)s, (int)c);
        static IOrderedEnumerable<T> OrderByRand<T>(this IEnumerable<T> x) => Enumerable.OrderBy(x, _ => xorshift);
        static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> x) => Enumerable.OrderBy(x.OrderByRand(), e => e);
        static IOrderedEnumerable<T1> OrderBy<T1, T2>(this IEnumerable<T1> x, Func<T1, T2> selector) => Enumerable.OrderBy(x.OrderByRand(), selector);
        static IOrderedEnumerable<T> OrderByDescending<T>(this IEnumerable<T> x) => Enumerable.OrderByDescending(x.OrderByRand(), e => e);
        static IOrderedEnumerable<T1> OrderByDescending<T1, T2>(this IEnumerable<T1> x, Func<T1, T2> selector) => Enumerable.OrderByDescending(x.OrderByRand(), selector);
        static IOrderedEnumerable<string> OrderBy(this IEnumerable<string> x) => x.OrderByRand().OrderBy(e => e, StringComparer.OrdinalIgnoreCase);
        static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> x, Func<T, string> selector) => x.OrderByRand().OrderBy(selector, StringComparer.OrdinalIgnoreCase);
        static IOrderedEnumerable<string> OrderByDescending(this IEnumerable<string> x) => x.OrderByRand().OrderByDescending(e => e, StringComparer.OrdinalIgnoreCase);
        static IOrderedEnumerable<T> OrderByDescending<T>(this IEnumerable<T> x, Func<T, string> selector) => x.OrderByRand().OrderByDescending(selector, StringComparer.OrdinalIgnoreCase);
        static uint xorshift { get { _xsi.MoveNext(); return _xsi.Current; } }
        static IEnumerator<uint> _xsi = _xsc();
        static IEnumerator<uint> _xsc() { uint x = 123456789, y = 362436069, z = 521288629, w = (uint)(DateTime.Now.Ticks & 0xffffffff); while (true) { var t = x ^ (x << 11); x = y; y = z; z = w; w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)); yield return w; } }
    }
}
namespace Library {
    class LIB_FastIO
    {
        public LIB_FastIO() { str = Console.OpenStandardInput(); }
        readonly Stream str;
        readonly byte[] buf = new byte[1024];
        int len, ptr;
        public bool isEof = false;
        public bool IsEndOfStream { get { return isEof; } }
        byte read()
        {
            if (isEof) throw new EndOfStreamException();
            if (ptr >= len)
            {
                ptr = 0;
                if ((len = str.Read(buf, 0, 1024)) <= 0)
                {
                    isEof = true;
                    return 0;
                }
            }
            return buf[ptr++];
        }
        char Char()
        {
            byte b = 0;
            do b = read();
            while (b < 33 || 126 < b);
            return (char)b;
        }
        virtual public string Scan()
        {
            var sb = new StringBuilder();
            for (var b = Char(); b >= 33 && b <= 126; b = (char)read())
                sb.Append(b);
            return sb.ToString();
        }
        virtual public long Long()
        {
            long ret = 0; byte b = 0; var ng = false;
            do b = read();
            while (b != '-' && (b < '0' || '9' < b));
            if (b == '-') { ng = true; b = read(); }
            for (; true; b = read())
            {
                if (b < '0' || '9' < b)
                    return ng ? -ret : ret;
                else ret = ret * 10 + b - '0';
            }
        }
        virtual public double Double() { return double.Parse(Scan(), CultureInfo.InvariantCulture); }
    }
    class LIB_FastIODebug : LIB_FastIO
    {
        Queue<string> param = new Queue<string>();
        string NextString() { if (param.Count == 0) foreach (var item in Console.ReadLine().Split(' ')) param.Enqueue(item); return param.Dequeue(); }
        public LIB_FastIODebug() { }
        public override string Scan() => NextString();
        public override long Long() => long.Parse(NextString());
        public override double Double() => double.Parse(NextString());
    }
    class LIB_Geo2D
    {
        static readonly public double EPS = 1e-10;
        public struct Vec
        {
            public double x;
            public double y;
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            public Vec(double x, double y) { this.x = x; this.y = y; }
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            static public Vec operator +(Vec a, Vec b) => new Vec() { x = a.x + b.x, y = a.y + b.y };
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            static public Vec operator -(Vec a, Vec b) => new Vec() { x = a.x - b.x, y = a.y - b.y };
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            static public Vec operator *(Vec p, double v) => new Vec() { x = p.x * v, y = p.y * v };
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            static public Vec operator *(double v, Vec p) => p * v;
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            static public Vec operator /(Vec p, double v) => new Vec() { x = p.x / v, y = p.y / v };
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            static public Vec operator /(double v, Vec p) => p / v;
        }
        public struct Line
        {
            public double a;
            public double b;
            public double c;
            /// <summary>
            /// ax + by + c = 0
            /// </summary>
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            public Line(double a, double b, double c) { this.a = a; this.b = b; this.c = c; }
        }
        public struct Circle
        {
            public Vec p;
            /// <summary>
            /// 半径の2乗
            /// </summary>
            public double r2;
            /// <summary>
            /// 半径
            /// </summary>
            public double r
            {
                [MethodImpl(MethodImplOptions.AggressiveInlining)]
                get { return Sqrt(r2); }
                private set { }
            }
        }
        /// <summary>
        /// 点と点の距離の2乗を求める
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public double Distance(Vec p1, Vec p2) => Norm(p2 - p1);
        /// <summary>
        /// 点と円の距離の2乗を求める。負の場合は円の内側にいる（絶対値は一番近い円の縁までの距離）
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public double Distance(Vec p, Circle c) => Norm(p - c.p) - c.r2;
        /// <summary>
        /// 点と円の距離の2乗を求める。負の場合は円の内側にいる（絶対値は一番近い円の縁までの距離）
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public double Distance(Circle c, Vec p) => Norm(p - c.p) - c.r2;
        /// <summary>
        /// 円と直線の交点を求める
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public Vec[] Intersection(Line l, Circle c) => Intersection(c, l);
        /// <summary>
        /// 円と直線の交点を求める
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public Vec[] Intersection(Circle c, Line l)
        {
            var d = l.a * c.p.x + l.b * c.p.y + l.c;
            var ab2 = (l.a * l.a + l.b * l.b);
            var d2 = ab2 * c.r2 - d * d;
            if (d2 < -EPS) return new Vec[0];
            if (d2 > EPS)
            {
                var rd = Sqrt(d2);
                var p1 = new Vec((-l.a * d + l.b * rd) / ab2 + c.p.x, (-l.b * d - l.a * rd) / ab2 + c.p.y);
                var p2 = new Vec((-l.a * d - l.b * rd) / ab2 + c.p.x, (-l.b * d + l.a * rd) / ab2 + c.p.y);
                return new[] { p1, p2 };
            }
            return new[] { new Vec(-l.a * d / ab2 + c.p.x, -l.b * d / ab2 + c.p.y) };
        }
        /// <summary>
        /// 円と円の交点を求める
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public Vec[] Intersection(Circle c1, Circle c2)
        {
            var p = c2.p - c1.p;
            var b = p.x * p.x + p.y * p.y;
            var a = (b + c1.r2 - c2.r2) / 2;
            var d = b * c1.r2 - a * a;
            if (d < -EPS) return new Vec[0];
            if (d > EPS)
            {
                var c = Sqrt(d);
                var p1 = new Vec((a * p.x + p.y * c) / b + c1.p.x, (a * p.y - p.x * c) / b + c1.p.y);
                var p2 = new Vec((a * p.x - p.y * c) / b + c1.p.x, (a * p.y + p.x * c) / b + c1.p.y);
                return new[] { p1, p2 };
            }
            return new[] { new Vec(a * p.x / b + c1.p.x, a * p.y / b + c1.p.y) };
        }
        /// <summary>
        /// pの長さの2乗を得る
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public double Norm(Vec p) => p.x * p.x + p.y * p.y;
        /// <summary>
        /// 内積
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public double Dot(Vec p1, Vec p2) => p1.x * p2.x + p1.y * p2.y;
        /// <summary>
        /// 外積（平行四辺形の面積）負になり得る
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public double Cross(Vec p1, Vec p2) => p1.x * p2.y - p1.y * p2.x;
        /// <summary>
        /// 3点を通る円を返す
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public Circle GetCircleFrom3Vec(Vec p1, Vec p2, Vec p3)
        {
            var A = Distance(p2, p3);
            var B = Distance(p1, p3);
            var C = Distance(p1, p2);
            var S = Abs(Cross(p2 - p1, p3 - p1));
            var p = (A * (B + C - A) * p1 + B * (C + A - B) * p2 + C * (A + B - C) * p3) / (4 * S * S);
            var r = Distance(p, p1);
            return new Circle() { p = p, r2 = r };
        }
        /// <summary>
        /// 2点を通る円を返す
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public Circle GetCircleFrom2Vec(Vec p1, Vec p2)
        {
            var c = (p1 + p2) / 2;
            return new Circle() { p = c, r2 = Distance(p1, c) };
        }
        /// <summary>
        /// 最小包含円を返す
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static public Circle GetEncloseCircle(IEnumerable<Vec> pointList)
        {
            var pList = pointList.ToArray();
            if (pList.Length < 2) throw new Exception();
            var rnd = new Random();
            var list = pList.OrderBy(_ => rnd.Next()).ToArray();
            Func<Vec, Circle, bool> inCircle = null;
            inCircle = (p, c) => Distance(p, c) < EPS;
            {
                var c = GetCircleFrom2Vec(list[0], list[1]);
                for (var i = 2; i < list.Length; i++)
                {
                    if (!inCircle(list[i], c))
                    {
                        c = GetCircleFrom2Vec(list[0], list[i]);
                        for (var j = 1; j < i; j++)
                        {
                            if (!inCircle(list[j], c))
                            {
                                c = GetCircleFrom2Vec(list[i], list[j]);
                                for (var k = 0; k < j; k++)
                                {
                                    if (!inCircle(list[k], c))
                                    {
                                        c = GetCircleFrom3Vec(list[i], list[j], list[k]);
                                    }
                                }
                            }
                        }
                    }
                }
                return c;
            }
        }
    }
}