#[allow(unused_imports)]
use std::cmp::{max, min, Ordering};
#[allow(unused_imports)]
use std::collections::{HashMap, HashSet, BinaryHeap};
#[allow(unused_imports)]
use std::iter::FromIterator;
#[allow(unused_imports)]
use std::io::stdin;

use std::f64;

mod util {
    use std::io::stdin;
    use std::str::FromStr;
    use std::fmt::Debug;

    #[allow(dead_code)]
    pub fn line() -> String {
        let mut line: String = String::new();
        stdin().read_line(&mut line).unwrap();
        line.trim().to_string()
    }

    #[allow(dead_code)]
    pub fn gets<T: FromStr>() -> Vec<T>
    where
        <T as FromStr>::Err: Debug,
    {
        let mut line: String = String::new();
        stdin().read_line(&mut line).unwrap();
        line.split_whitespace()
            .map(|t| t.parse().unwrap())
            .collect()
    }
}

#[allow(unused_macros)]
macro_rules! get {
    ($t:ty) => {
        {
            let mut line: String = String::new();
            stdin().read_line(&mut line).unwrap();
            line.trim().parse::<$t>().unwrap()
        }
    };
    ($($t:ty),*) => {
        {
            let mut line: String = String::new();
            stdin().read_line(&mut line).unwrap();
            let mut iter = line.split_whitespace();
            (
                $(iter.next().unwrap().parse::<$t>().unwrap(),)*
            )
        }
    };
}

#[allow(unused_macros)]
macro_rules! debug {
    ($($a:expr),*) => {
        println!(concat!($(stringify!($a), " = {:?}, "),*), $($a),*);
    }
}

#[derive(Eq, PartialEq, Clone, Debug)]
struct Rev<T>(pub T);

impl<T: PartialOrd> PartialOrd for Rev<T> {
    fn partial_cmp(&self, other: &Rev<T>) -> Option<Ordering> {
        other.0.partial_cmp(&self.0)
    }
}

impl<T: Ord> Ord for Rev<T> {
    fn cmp(&self, other: &Rev<T>) -> Ordering {
        other.0.cmp(&self.0)
    }
}

#[derive(PartialEq, PartialOrd)]
struct O<T>(pub T);

impl<T: PartialEq> Eq for O<T> {}

impl<T: PartialOrd> Ord for O<T> {
    fn cmp(&self, other: &O<T>) -> Ordering {
        self.0.partial_cmp(&other.0).unwrap()
    }
}

fn main() {
    let (xs, ys, xt, yt) = get!(f64, f64, f64, f64);
    let n = get!(usize);
    let mut bs: Vec<(f64, f64, f64)> = (0..n).map(|_| get!(f64, f64, f64)).collect();
    bs.push((xs, ys, 0.0));
    bs.push((xt, yt, 0.0));

    let mut edges = vec![vec![0.0; n + 2]; n + 2];
    for i in 0..n + 2 {
        for k in 0..n + 2 {
            let (x1, y1, r1) = bs[i];
            let (x2, y2, r2) = bs[k];

            let d = ((x1 - x2).powi(2) + (y1 - y2).powi(2)).sqrt();
            let cost = if r1 + r2 >= d { 0.0 } else { d - r1 - r2 };

            edges[i][k] = cost;
            edges[k][i] = cost;
        }
    }

    let mut ds = vec![f64::INFINITY; bs.len()];
    ds[n] = 0.0;
    let mut que = BinaryHeap::new();
    que.push(Rev((O(0.0), n)));

    while !que.is_empty() {
        let Rev((O(cost), here)) = que.pop().unwrap();
        if here == n + 1 {
            println!("{}", cost);
            return;
        }
        for to in 0..bs.len() {
            if here == to {
                continue;
            }
            let new_cost = cost + edges[here][to];
            if ds[to] > new_cost {
                ds[to] = new_cost;
                que.push(Rev((O(new_cost), to)));
            }
        }
    }
}


Measured memory_bytes: 17656