#include <bits/stdc++.h>

using namespace std;

typedef long long int64;

namespace Geometory
{
  struct Point
  {
    int64 x, y;

    Point() {};

    Point(int64 x, int64 y) : x(x), y(y) {};

    Point operator+(const Point &b) const { return Point(x + b.x, y + b.y); }

    Point operator-(const Point &b) const { return Point(x - b.x, y - b.y); }

    Point operator*(const double b) const { return Point(x * b, y * b); }

    Point operator*(const Point &b) const { return Point(x * b.x - y * b.y, x * b.y + y * b.x); }

    Point operator/(const double b) const { return Point(x / b, y / b); }

    bool operator<(const Point &b) const { return x != b.x ? x < b.x : y < b.y; }

    bool operator==(const Point &b) const { return x == b.x && y == b.y; }

    int64 norm() { return x * x + y * y; }

    friend ostream &operator<<(ostream &os, Point &p) { return os << "(" << p.x << "," << p.y << ")"; }

    friend istream &operator>>(istream &is, Point &a) { return is >> a.x >> a.y; }
  };
};

struct UnionFind
{
  vector< int > data;

  UnionFind(int sz)
  {
    data.assign(sz, -1);
  }

  void unite(int x, int y)
  {
    x = find(x), y = find(y);
    if(x != y) {
      if(data[x] > data[y]) swap(x, y);
      data[x] += data[y];
      data[y] = x;
    }
  }

  int find(int k)
  {
    if(data[k] < 0) return (k);
    return (data[k] = find(data[k]));
  }

  int size(int k)
  {
    return (-data[find(k)]);
  }
};

typedef long long int64;

struct edge
{
  int to;
  double cost;
};
typedef vector< vector< edge > > Graph;
const double INF = 1e18;

typedef pair< double, int > Pi;

double Dijkstra(Graph &graph, int s, int g)
{
  vector< double > min_cost(graph.size(), INF);
  priority_queue< Pi, vector< Pi >, greater< Pi > > que;
  que.push(make_pair(0, s));
  min_cost[s] = 0;
  while(!que.empty()) {
    int now = que.top().second;
    double cost = que.top().first;
    que.pop();
    if(now == g) return (cost);
    if(cost > min_cost[now]) continue;
    for(int i = 0; i < graph[now].size(); i++) {
      edge &e = graph[now][i];
      if(cost + e.cost < min_cost[e.to]) {
        min_cost[e.to] = cost + e.cost;
        que.push(make_pair(min_cost[e.to], e.to));
      }
    }
  }
  return (-1);
}

int main()
{
  Geometory::Point s, t;

  cin >> s >> t;
  int N;
  cin >> N;
  vector< Geometory::Point > cc(N);
  vector< int64 > cr(N);
  for(int i = 0; i < N; i++) {
    cin >> cc[i] >> cr[i];
  }
  UnionFind uf(N + 2);
  for(int i = 0; i < N; i++) {
    for(int j = i + 1; j < N; j++) {
      if((cc[i] - cc[j]).norm() <= (cr[i] + cr[j]) * (cr[i] + cr[j])) uf.unite(i, j);
    }
    if((s - cc[i]).norm() <= cr[i] * cr[i]) uf.unite(N, i);
    if((t - cc[i]).norm() <= cr[i] * cr[i]) uf.unite(N + 1, i);
  }
  cout << fixed << setprecision(15);

  if(uf.find(N) == uf.find(N + 1)) {
    cout << 0 << endl;
  } else {
    vector< vector< edge > > g(N + 2);
    for(int i = 0; i < N; i++) {
      for(int j = i + 1; j < N; j++) {
        int a = uf.find(i);
        int b = uf.find(j);
        if(a == b) continue;
        double ts = sqrt((cc[i] - cc[j]).norm()) - cr[i] - cr[j];
        g[a].push_back((edge) {b, ts});
        g[b].push_back((edge) {a, ts});
      }
      if(uf.find(N) != uf.find(i)) {
        double ts = sqrt((s - cc[i]).norm()) - cr[i];
        g[uf.find(N)].push_back((edge) {uf.find(i), ts});
        g[uf.find(i)].push_back((edge) {uf.find(N), ts});
      }
      if(uf.find(N + 1) != uf.find(i)) {
        double ts = sqrt((t - cc[i]).norm()) - cr[i];
        g[uf.find(N + 1)].push_back((edge) {uf.find(i), ts});
        g[uf.find(i)].push_back((edge) {uf.find(N + 1), ts});
      }
    }
    g[uf.find(N)].push_back((edge) {uf.find(N + 1), sqrt((s - t).norm())});
    cout << Dijkstra(g, uf.find(N), uf.find(N + 1)) << endl;
  }
}

Measured memory_bytes: 20720