#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for(int i = 0; i < n; i++)
#define rep2(i, x, n) for(int i = x; i <= n; i++)
#define rep3(i, x, n) for(int i = x; i >= n; i--)
#define elif else if
#define sp setprecision
#define pb(x) push_back(x)
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<int, ll> pil;
typedef pair<ll, int> pli;
typedef pair<ld, ld> pdd;
const ll MOD = 1e9+7;
//const ll MOD = 998244353;
const int inf = 1e8;
const ll INF = 1e16;
const string alpha = "abcdefghijklmnopqrstuvwxyz";

//点a,bの距離の2乗
ld dist2(pdd a, pdd b){
    ld x = b.first - a.first;
    ld y = b.second - a.second;
    return x*x + y*y;
}

//点a,bの距離
ld dist(pdd a, pdd b){
    return sqrt(dist2(a, b));
}

//aのノルムの2乗
ld norm2(pdd a){
    return(a.first*a.first + a.second*a.second);
}

//aのノルム
ld norm(pdd a){
    return sqrt(norm2(a));
}

//内積a・b
ld dot(pdd a, pdd b){
    ld x = a.first * b.first;
    ld y = a.second * b.second;
    return x+y;
}

//a,bを横に並べた行列の行列式
ld det(pdd a, pdd b){
    ld x = a.first * b.second;
    ld y = a.second * b.first;
    return x-y;
}

//b-a
pdd dif(pdd a, pdd b){
    pdd p;
    p.first = b.first - a.first;
    p.second = b.second - a.second;
    return p;
}

//点a,bの中点
pdd mid(pdd a, pdd b){
    pdd p;
    p.first = (a.first + b.first)/2;
    p.second = (a.second + b.second)/2;
    return p;
}

//点a,bをs:tに内分する点
pdd ind(pdd a, pdd b, ld s, ld t){
    pdd p;
    p.first = (t*a.first+s*b.first)/(s+t);
    p.second = (t*a.second+s*b.second)/(s+t);
    return p;
}

//点a,bをs:tに外分する点
pdd exd(pdd a, pdd b, ld s, ld t){
    return ind(a, b, s, -t);
}

typedef vector<pdd> vec;

//直線a1x+b1y=c1と直線a2x+b2y=c2の交点
vec l_l(ld a1, ld b1, ld c1, ld a2, ld b2, ld c2){
    vec res;
    if(a1*b2 == a2*b1) return res;
    ld x = (c1*b2-c2*b1)/(a1*b2-a2*b1);
    ld y = (c1*a2-c2*a1)/(b1*a2-b2*a1);
    res.pb(pdd(x, y));
    return res;
}

//直線ax+by=cと円(x-p)^2+(y-q)^2=r^2の交点
vec l_c(ld a, ld b, ld c, ld p, ld q, ld r){
    vec res;
      if(a == 0 & b == 0) return res;
    //直線と円の中心の距離
    ld d = abs(a*p+b*q-c)/sqrt(a*a+b*b);
    if(d > r) return res;
    //hx,hy:=円の中心から直線に下ろした垂線の足の座標
    ld hx = (a*c-b*(a*q-b*p))/(a*a+b*b);
    ld hy = (b*c+a*(a*q-b*p))/(a*a+b*b);
    if(d == r){
        res.pb(pdd(hx, hy));
        return res;
    }
    //d2:=垂線の足hと交点の距離
    ld d2 = sqrt(r*r-d*d);
    //ex,ey:=直線と同じ向きの単位ベクトル
    ld ex = -b/sqrt(a*a+b*b), ey = a/sqrt(a*a+b*b);
    res.pb(pdd(hx+d2*ex, hy+d2*ey));
    res.pb(pdd(hx-d2*ex, hy-d2*ey));
    return res;
}

//円(x-p1)^2+(y-q1)^2=r1^2と円(x-p2)^2+(y-q2)^2=r2^2の交点
vec c_c(ld p1, ld q1, ld r1, ld p2, ld q2, ld r2){
    //直線ax+by=c:=２つの円の交点を通る直線
    ld a = 2*(p1-p2), b = 2*(q1-q2), c = (p1*p1+q1*q1-r1*r1)-(p2*p2+q2*q2-r2*r2);
    return l_c(a, b, c, p1, q1, r1);
}

//点a,bの垂直二等分線
vector<ld> ver(pdd a, pdd b){
    ld p = a.first, q = a.second, r = b.first, s = b.second;
    vector<ld> res(3);
    res[0] = r-p;
    res[1] = s-q;
    res[2] = (r*r-p*p+s*s-q*q)/2;
    return res;
}

const int MAX_V = 2e3;

struct union_find_tree{
    int par[MAX_V], rank[MAX_V], num[MAX_V];
    //要素数n(0〜n-1)の初期化されたUnion-Find木を構築
    union_find_tree(int N){
        rep(i, N){par[i] = i, rank[i] = 0, num[i] = 1;}
    }
    //ノードxの根を取得
    int find(int x){
        if(par[x] == x) return x;
        else return find(par[x]);
    }
    //xとyの属する集合を併合
    void unite(int x, int y){
        x = find(x), y = find(y);
        if(x == y) return;
        elif(rank[x] < rank[y]){par[x] = y, num[y] += num[x];}
        else{
            par[y] = x, num[x] += num[y];
            if(rank[x] == rank[y]) rank[x]++;
        }
    }
    //xの属する集合の要素数を取得
    int size(int x){
        return num[find(x)];
    }
    //xとyが同じ集合に属するか判定
    bool same(int x, int y){
        return find(x) == find(y);
    }
};

struct edge{
    int to;
    ld cost;
};

//V:=頂点数、E:=辺数
int V, E;
//const int MAX_V = 2e5;
vector<edge> es[MAX_V];
ld d[MAX_V];
typedef pair<ld, int> pdi;

//グラフに負の辺がない場合に、O(M*log(N))でsから全ての点への最短距離をそれぞれ求める
void dijkstra(int s){
    priority_queue<pdi, vector<pdi>, greater<pdi> > que;
    fill(d, d+V, INF);
    d[s] = 0;
    que.push(pdi(0, s));
    while(!que.empty()){
        pdi p = que.top();
        que.pop();
        int v = p.second;
        //d[v]が確定している
        if(d[v] < p.first) continue;
        for(auto &e: es[v]){
            if(d[e.to] > d[v]+e.cost){
                d[e.to] = d[v]+e.cost;
                que.push(pdi(d[e.to], e.to));
            }
        }
    }
}

int main(){
    pdd s, t;
    cin >> s.first >> s.second >> t.first >> t.second;
    int N;
    cin >> N;
    pdd p[N+2];
    ld r[N+2];
    p[0] = s, r[0] = 0;
    rep2(i, 1, N){
        cin >> p[i].first >> p[i].second >> r[i];
    }
    p[N+1] = t, r[N+1] = 0;
    union_find_tree uft(N+2);
    rep(i, N+2){
        rep2(j, i+1, N+1){
            if(dist(p[i], p[j]) <= r[i]+r[j]) uft.unite(i, j);
        }
    }
    map<int, int> mp;
    rep(i, N+2){
        mp[uft.find(i)]++;
    }
    //n個の島がある
    int n = 0;
    for(auto &e: mp){
        e.second = n;
        n++;
    }
    V = n;
    //s,tはどこの島に所属しているか
    int st = mp[uft.find(0)], en = mp[uft.find(N+1)];
    //cs[i]:=番号iの島に含まれる点の集合
    vector<int> cs[n];
    rep(i, N+2){
        cs[mp[uft.find(i)]].pb(i);
        //cout << i << ' ' << mp[uft.find(i)] << endl;
    }
    //D[i][j]:=島i,jの距離
    rep(i, n) rep2(j, i+1, n-1){
        ld D = 1e10;
        for(auto &u: cs[i]) for(auto &v: cs[j]){
            D = min(D, dist(p[u], p[v]) - r[u]-r[v]);
        }
        edge e1 = {j, D}, e2 = {i, D};
        es[i].pb(e1), es[j].pb(e2);
    }
    dijkstra(st);
    cout << fixed << sp(15) << d[en] << endl;
}

Measured memory_bytes: 43056