#include <bits/stdc++.h>

#define M_PI       3.14159265358979323846   // pi

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<ll> VI;
typedef pair<ll, ll> P;
typedef tuple<ll, ll, ll> t3;
typedef tuple<ll, ll, ll, ll> t4;
typedef tuple<ll, ll, ll, ll, ll> t5;

#define rep(a,n) for(ll a = 0;a < n;a++)
#define repi(a,b,n) for(ll a = b;a < n;a++)

using namespace std;

static const ll INF = 1e15;

template<typename T>
static inline void chmin(T & ref, const T  value) {
    if (ref > value) ref = value;
}

template<typename T>
static inline void chmax(T & ref, const T value) {
    if (ref < value) ref = value;
}

struct warshall_floyd {
    static void solve(vector<vector<ll>>& d) {
        int n = d.size();
        rep(k, n) {
            rep(i, n) {
                rep(j, n) {
                    d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
                }
            }
        }
    }
};


struct edge {
    int from;
    int to;
    double cost;
    edge(){}
    edge(int a, int b, double c) : from(a), to(b), cost(c){}
};

struct UnionFind {
public:
    vector <ll> par; // 
    vector <ll> siz; // 

    UnionFind(ll sz_) : par(sz_), siz(sz_, 1LL) {
        for (ll i = 0; i < sz_; ++i) par[i] = i;
    }
    void init(ll sz_) {
        par.resize(sz_);
        siz.assign(sz_, 1LL);
        for (ll i = 0; i < sz_; ++i) par[i] = i;
    }

    ll root(ll x) {
        while (par[x] != x) {
            x = par[x] = par[par[x]];
        }
        return x;
    }

    bool merge(ll x, ll y) {
        x = root(x);
        y = root(y);
        if (x == y) return false;
        if (siz[x] < siz[y]) swap(x, y);
        siz[x] += siz[y];
        par[y] = x;
        return true;
    }

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

    ll size(ll x) {
        return siz[root(x)];
    }
};

struct KruskalRunner {
    static bool orderByCost(const edge& e1, const edge& e2) {
        return e1.cost < e2.cost;
    }

    double solve(int vCount, vector<edge>& edges) {
        sort(edges.begin(), edges.end(), orderByCost);
        UnionFind uf = UnionFind(vCount);
        double sum = 0;
        for (int i = 0; i < edges.size(); ++i) {
            edge e = edges[i];
            if (!uf.issame(e.from, e.to)) {
                uf.merge(e.from, e.to);
                sum += e.cost;
            }
        }
        return sum;
    }
};

struct vector4 {
    double x, y, z, r;

    vector4 sub(vector4 o) {
        vector4 diff;
        diff.x = x - o.x;
        diff.y = y - o.y;
        diff.z = z - o.z;
        diff.r = r - o.r;
        return diff;
    }
};

int main() {
    vector<double> as;
    while (true) {
        int n;
        cin >> n;
        if (n == 0) {
            cout << fixed << setprecision(3);
            for (auto p : as) {
                cout << p << endl;
            }
            return 0;
        }
        vector<vector4> cs(n);
        rep(i, n) {
            cin >> cs[i].x;
            cin >> cs[i].y;
            cin >> cs[i].z;
            cin >> cs[i].r;
        }
        vector<vector<double>> dist(n, vector<double>(n, 0));
        rep(i, n) {
            rep(j, n) {
                if (i == j) continue;
                vector4 diff = cs[i].sub(cs[j]);
                double dr2 = diff.x * diff.x + diff.y * diff.y+ diff.z * diff.z;
                double d = sqrt(dr2);
                double rsum = cs[i].r + cs[j].r;
                dist[i][j] = max(0., d - rsum);
            }
        }
        vector<edge> edges;
        rep(i, n) {
            rep(j, i) {
                edges.emplace_back(i, j, dist[i][j]);
            }
        }
        KruskalRunner r;
        auto ans = r.solve(n, edges);
        as.push_back(ans);
    }
    return 0;
}




Measured memory_bytes: 3348