//include
//------------------------------------------
#include <vector>
#include <list>
#include <map>
#include <climits>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <queue>
#include <random>
#include <cctype>
#include <complex>
#include <regex>

using namespace std;

#define C_MAX(a, b) ((a)>(b)?(a):(b))
#define SHOW_VECTOR(v) {std::cerr << #v << "\t:";for(const auto& xxx : v){std::cerr << xxx << " ";}std::cerr << "\n";}
#define SHOW_MAP(v) {std::cerr << #v << endl; for(const auto& xxx: v){std::cerr << xxx.first << " " << xxx.second << "\n";}}

//切り上げ
double ceil_n(double dIn, int nLen) {
    double dOut;
    dOut = dIn * pow(10.0, nLen);
    dOut = (double) (int) (dOut + 0.9);
    return dOut * pow(10.0, -nLen);
}

//切り捨て
double floor_n(double dIn, int nLen) {
    double dOut;
    dOut = dIn * pow(10.0, nLen);
    dOut = (double) (int) (dOut);
    return dOut * pow(10.0, -nLen);
}

//四捨五入
double round_n(double dIn, int nLen) {
    double dOut;
    dOut = dIn * pow(10.0, nLen);
    dOut = (double) (int) (dOut + 0.5);
    return dOut * pow(10.0, -nLen);
}

struct Sphere {
    double x;
    double y;
    double z;
    double r;
};

struct edge {
    int from;
    int to;
    double cost;
};

double distance_center(Sphere s1, Sphere s2) {
    double dx = abs(s1.x - s2.x);
    double dy = abs(s1.y - s2.y);
    double dz = abs(s1.z - s2.z);
    return sqrt(dx * dx + dy * dy + dz * dz);
}

double distance_edge(Sphere s1, Sphere s2) {
    double distance = distance_center(s1, s2);
    distance -= (s1.r + s2.r);
    return distance;
}

struct UnionFind {

    vector<int> par;
    vector<int> sizes;

    UnionFind(int N) :
            par(N),
            sizes(N, 1) {
        for (int i = 0; i < N; i++)par[i] = i;
    }

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

    void unite(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) return;
        if (sizes[x] < sizes[y]) swap(x, y);
        par[y] = x;
        sizes[x] += sizes[y];
    }

    bool same(int x, int y) {
        return find(x) == find(y);
    }

    int getSize(int x) {
        return sizes[find(x)];
    }

};

bool comp(const edge &e1, const edge &e2) {
    return e1.cost < e2.cost;
}

int main() {

    while (true) {

        int N;
        cin >> N;

        if (N == 0) break;

        vector<Sphere> spheres(N);

        for (int i = 0; i < N; i++) {
            double x, y, z, r;
            cin >> x >> y >> z >> r;
            spheres[i] = (Sphere) {x, y, z, r};
        }

        vector<edge> edges;
        UnionFind UF(N);

        for (int i = 0; i < N; i++) {
            for (int j = i; j < N; j++) {
                if (i == j) continue;
                double distance = distance_edge(spheres[i], spheres[j]);
                if (distance > 0.001) {
                    edges.push_back((edge) {i, j, distance});
                } else {
                    UF.unite(i, j);
                }
            }
        }

        sort(edges.begin(), edges.end(), comp);

        double ans = 0;
        for (int i = 0; i < edges.size(); i++) {
            edge e = edges[i];
            if (!UF.same(e.from, e.to)) {
                UF.unite(e.from, e.to);
                ans += e.cost;
            }
        }

        ans = round_n(ans, 3);
        cout << fixed << setprecision(3) << ans << endl;

    }

    return 0;
}





























Measured memory_bytes: 3452