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

struct UnionFind
{
    vector<int> par;
    UnionFind(int n) : par(n, -1){ }
    int root(int x){
        if(par[x] < 0) return x;
        else return par[x] = root(par[x]);
    }
    bool issame(int x, int y){
        return root(x) == root(y);
    }
    bool merge(int x, int y){
        x = root(x); y = root(y);
        if(x == y) return false;
        if(par[x] > par[y]) swap(x, y);
        par[x] += par[y];
        par[y] = x;
        return true;
    }
    int size(int x){
        return -par[root(x)];
    }
};

struct Edge
{
    int a, b;
    double dist;
    bool operator<(const Edge& o) const{
        return dist < o.dist;
    }
};

struct Graph
{
    int n;
    vector<Edge> es;

    double kruskal(){
        sort(es.begin(), es.end());

        UnionFind uf(n);
        double min_dist = 0;
        for (int ei = 0; ei < es.size(); ei++)
        {
            Edge& e = es[ei];
            if(!uf.issame(e.a, e.b)){
                min_dist += e.dist;
                uf.merge(e.a, e.b);
            }
        }
        return min_dist;
    }
};

double d(double x, double y, double z, double u, double v, double w){
    double dx = x - u, dy = y - v, dz = z - w;
    return sqrt(dx * dx + dy * dy + dz * dz);
}

int N;
int main() {
    while (true)
    {
        cin >> N;
        double in[N][4];
        if(N == 0) break;
        for (int i = 0; i < N; i++)
        {
            cin >> in[i][0] >> in[i][1] >> in[i][2] >> in[i][3];
        }

        Graph g;
        g.n = N;
        for (int i = 0; i < N; i++)
        {
            for (int j = i+1; j < N; j++)
            {
                Edge e;
                e.a = i, e.b = j;
                e.dist = max((double)0, d(in[i][0], in[i][1], in[i][2], in[j][0], in[j][1], in[j][2]) - in[i][3] - in[j][3]);
                g.es.push_back(e);
            }
        }
        cout << fixed << setprecision(3) << g.kruskal() << endl;
    }

}
