use std::{cmp::{max, min, Reverse}, collections::{BTreeMap, BTreeSet, VecDeque, BinaryHeap} };

fn read_line() -> String {
    let mut buffer = String::new();
    std::io::stdin().read_line(&mut buffer).expect("No Line");
    buffer
}
fn read_lines<R, T: Fn(&str)->R> (count: usize, transformer: T) -> Vec<R> {
    let mut buffer = String::new();
    let mut vec = Vec::with_capacity(count);
    for _ in 0 .. count {
        std::io::stdin().read_line(&mut buffer).expect("No Line");
        vec.push(transformer(buffer.trim()));
    }
    vec
}
fn read_value<T: std::str::FromStr>() -> T {
    read_line().trim().parse().ok().unwrap()
}
fn read_values<T: std::str::FromStr>() -> Vec<T> {
    read_line().trim().split(' ').map(|x| x.parse().ok().expect("Can't Parse")).collect::<Vec<T>>()
}
fn read_tabulate<T: std::str::FromStr>(count: usize) -> Vec<T> {
    let mut buffer = String::new();
    let mut vec = Vec::with_capacity(count);
    for _ in 0 .. count {
        std::io::stdin().read_line(&mut buffer).expect("No Line");
        vec.push(buffer.parse().ok().expect("Can't Parse"));
    }
    vec
}
macro_rules! assign {
    () => {};
    ($($token:tt)*) => {
        let mut iter = read_values::<String>().into_iter();
        assign_iter!(iter, $($token)*);
    };
}
macro_rules! assign_iter {
    ($iter:expr) =>{};
    ($iter:expr,) =>{};
    ($iter:expr, $id:ident:$t:tt $($tail:tt)*) => {
        let $id: $t = $iter.next().unwrap().parse().ok().expect("Can't Parse");
        assign_iter!($iter, $($tail)*);
    };
    ($iter:expr, mut $id:ident:$t:tt $($tail:tt)*) => {
        let mut $id: $t = $iter.next().unwrap().parse().ok().expect("Can't Parse");
        assign_iter!($iter, $($tail)*)
    };
}
macro_rules! freeze {
    ($($id:ident), *) => {
        $(let $id = $id;)*
    };

}

#[derive(Copy, Clone)]
struct Coordinate {
    x: f64,
    y: f64
}
struct Circle {
    center: Coordinate,
    radius: f64
}
trait DistanceCalc<Rhs = Self> {
    type Output;
    fn distance(&self, rhs: &Rhs) -> Self::Output;
}
impl DistanceCalc<Coordinate> for Coordinate{
    type Output = f64;
    fn distance(&self, rhs: &Coordinate) -> Self::Output {
        ((self.x - rhs.x) * (self.x - rhs.x) + (self.y - rhs.y) * (self.y - rhs.y)).sqrt()
    }
}
impl DistanceCalc<Circle> for Circle {
    type Output = f64;
    fn distance(&self, rhs: &Circle) -> Self::Output {
        let dist = self.center.distance(&rhs.center) - self.radius - rhs.radius;
        match dist.partial_cmp(&0f64) {
            Some(std::cmp::Ordering::Greater) => dist,
            _ => 0f64
        }
    }
}
struct KeyValue<K, V>{
    key: K, 
    value: V
}
impl <K: Clone, V: Clone> Clone for KeyValue<K, V> {
    fn clone(&self) -> Self {
        KeyValue{key: self.key.clone(), value: self.value.clone()}
    }
}
impl <K: PartialEq, V> PartialEq for KeyValue<K, V> {
    fn eq(&self, other: &Self) -> bool {
        self.key.eq(&other.key)
    }
}
impl <K: PartialEq, V> Eq for KeyValue<K, V> {}
impl <K: PartialOrd, V> PartialOrd for KeyValue<K, V> {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        self.key.partial_cmp(&other.key)
    }
}
impl <K: PartialOrd, V> Ord for KeyValue<K, V> {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        match self.key.partial_cmp(&other.key) {
            Some(r) => r,
            None => panic!("Can\'t Compare"),
        }
    }
}
fn main() {
    assign!{
        sx: f64
        sy: f64
        gx: f64
        gy: f64
    }
    let start = Coordinate{x: sx, y: sy};
    let goal = Coordinate{x: gx, y: gy};
    assign!{
        n: usize
    }
    let mut barrier = Vec::with_capacity(n);
    for _ in 0 .. n {
        assign!{
            x: f64
            y: f64
            r: f64
        }
        barrier.push(Circle{center: Coordinate{x, y}, radius: r});
    }
    freeze!(barrier);
    let mut min_time = vec![std::f64::MAX; n];
    let mut priority_queue = BinaryHeap::new();
    for i in 0usize .. n {
        let dist = Circle{center: start, radius: 0f64}.distance(&barrier[i]);
        min_time[i] = dist;
        priority_queue.push(Reverse(KeyValue{key: dist, value: i}));
    }
    while let Some(Reverse(KeyValue{key: cost, value: current})) = priority_queue.pop() {
        if cost > min_time[current] {continue;}
        for i in 0usize .. n {
            if i == current {continue;}
            let dist = barrier[current].distance(&barrier[i]);
            if min_time[i] > dist + cost {
                min_time[i] = dist + cost;
                priority_queue.push(Reverse(KeyValue{key: min_time[i], value: i}));
            }
        }
    }
    let mut min = start.distance(&goal);
    for i in 0usize .. n {
        let dist = Circle{center: goal, radius: 0f64}.distance(&barrier[i]);
        min_time[i] += dist;
        if min_time[i] < min {
            min = min_time[i];
        }
    }
    println!("{:.15}", min);

}

Measured memory_bytes: 6164