#include <bits/stdc++.h>
using namespace std;


// type {{{
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using P = pair<int,int>;
using vi = vector<int>;
using vll = vector<ll>;
using vvi = vector<vector<int>>;
using vvll = vector<vector<ll>>;
// }}}


// macro {{{
#define REP(i,n) for (int i=0; i<(n); ++i)
#define RREP(i,n) for (int i=(int)(n)-1; i>=0; --i)
#define FOR(i,a,n) for (int i=(a); i<(n); ++i)
#define RFOR(i,a,n) for (int i=(int)(n)-1; i>=(a); --i)

#define SZ(x) ((int)(x).size())
#define all(x) begin(x),end(x)
// }}}


// debug {{{
#define dump(x) cerr<<#x<<" = "<<(x)<<endl
#define debug(x) cerr<<#x<<" = "<<(x)<<" (L"<<__LINE__<<")"<< endl;

template<typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
    os << "[";
    REP (i, SZ(v)) {
        if (i) os << ", ";
        os << v[i];
    }
    return os << "]";
}

template<typename T, typename U>
ostream& operator<<(ostream& os, const pair<T, U>& p) {
    return os << "(" << p.first << " " << p.second << ")";
}
// }}}


// chmax, chmin {{{
template<class T>
bool chmax(T& a, const T& b) {
    if (a < b) { a = b; return true; }
    return false;
}
template<class T>
bool chmin(T& a, const T& b) {
    if (b < a) { a = b; return true; }
    return false;
}
// }}}


// constants {{{
#define inf(T) (numeric_limits<T>::max() / 2)
const ll MOD = 1e9+7;
const ld EPS = 1e-9;
// }}}



struct UnionFind
{
    vector<int> par, sz;
    const int n;
    UnionFind(int n) : n(n), par(n), sz(n, 1) {
        for (int i = 0; i < n; ++i) par[i] = i;
    }

    int root(int x) {
        if (par[x] == x) return x;
        return par[x] = root(par[x]);
    }

    void merge(int x, int y) {
        x = root(x);
        y = root(y);
        if (x == y) return;
        if (sz[x] < sz[y]) swap(x, y);
        par[y] = x;
        sz[x] += sz[y];
        sz[y] = 0;
    }

    bool issame(int x, int y) {
        return root(x) == root(y);
    }

    int size(int x) {
        return sz[root(x)];
    }

    friend ostream& operator<<(ostream& os, UnionFind& uf) {
        os << "[";
        for (int i = 0; i < uf.n; ++i) {
            if (i > 0) os << " ";
            os << uf.root(i);
        }
        return os << "]" << endl;
    }
};

template<typename T>
struct edge {
    int src, to;
    T cost;
};
template<typename T>
T kruskal(const vector<edge<T>> &es, int V) {

    UnionFind uf(V);
    T ret = 0;

    vector<int> ord(es.size());
    iota(ord.begin(), ord.end(), 0);
    sort(ord.begin(), ord.end(), [&](int i,int j){
            return es[i].cost < es[j].cost;
            });

    for (auto i : ord) {
        auto &e = es[i];
        if (!uf.issame(e.src, e.to)) {
            ret += e.cost;
            uf.merge(e.src, e.to);
        }
    }

    return ret;
}


using Real = double;
const Real PI = acos(-1);

struct Point3D {
    double x, y, z;
    Point3D() {}
    Point3D(double x, double y, double z) : x(x), y(y), z(z) {}
    Point3D operator+(const Point3D& b) const {
        return Point3D(x + b.x, y + b.y, z + b.z);
    }
    Point3D operator-(const Point3D& b) const {
        return Point3D(x - b.x, y - b.y, z - b.z);
    }
    friend double norm(const Point3D& p) {
        return p.x * p.x + p.y * p.y + p.z * p.z;
    };
    friend double abs(const Point3D& p) { return sqrt(norm(p)); }

    friend ostream &operator<<(ostream &os, Point3D &p) {
        return os << "(" << p.x << "," << p.y << "," << p.z << ")";
    }
    friend istream &operator>>(istream &is, Point3D &p) {
        return is >> p.x >> p.y >> p.z;
    }
};
struct Segment3D {
    Point3D a, b;
    Segment3D() {}
    Segment3D(const Point3D& a, const Point3D& b) : a(a), b(b) {}
    friend ostream &operator<<(ostream &os, Segment3D &l) {
        return os << "[" << l.a << "," << l.b << "]";
    }
    friend istream &operator>>(istream &is, Segment3D &l) {
        return is >> l.a >> l.b;
    }
};

inline bool eq(Real a, Real b) { return abs(b - a) < EPS; }

double dot(const Point3D &a, const Point3D &b) {
    return a.x * b.x + a.y * b.y + a.z * b.z;
}

Point3D cross(const Point3D &a, const Point3D &b) {
    double x = a.y * b.z - a.z * b.y,
           y = a.z * b.x - a.x * b.z,
           z = a.x * b.y - a.y * b.x;
    return Point3D(x, y, z);
}

bool parallel(
        const Point3D &a1, const Point3D &a2,
        const Point3D &b1, const Point3D &b2) {
    return eq(abs(cross(a1-b1, a2-b2)), 0.0);
}

bool parallel(const Segment3D& l1, const Segment3D& l2) {
    return parallel(l1.a, l1.b, l2.a, l2.b);
}

double distance(const Segment3D &l, const Point3D &p) {
    if (dot(l.b - l.a, p - l.a) < EPS) return abs(p - l.a);
    if (dot(l.a - l.b, p - l.b) < EPS) return abs(p - l.b);
    return abs(cross(l.b - l.a, p - l.a)) / abs(l.b - l.a);
}


int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(3);

    for (;;) {
        int n; cin >> n;
        if (n == 0) break;

        vector<edge<double>> edges;
        vector<Point3D> points(n);
        vector<double> rs(n);
        REP(i, n) {
            cin >> points[i] >> rs[i];
        }
        REP(i, n) {
            FOR(j, i+1, n) {
                Point3D diff = points[i] - points[j];
                double dist = sqrt(dot(diff, diff));
                edges.push_back((edge<double>){ i, j, max(dist - rs[i] - rs[j], 0.0) });
            }
        }

        double ans = kruskal(edges, n);
        cout << ans << endl;
    }

    return 0;
}



Measured memory_bytes: 3456