// Header {{{
// includes {{{
#include <algorithm>
#include <cassert>
#include <cctype>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <iterator>
#include <limits>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <sys/time.h>
#include <unistd.h>
#include <vector>
// }}}
using namespace std;
// consts {{{
static const int INF = 1e9;
static const double PI = acos(-1.0);
static const double EPS = 1e-10;
// }}}
// typedefs {{{
typedef long long int LL;
typedef unsigned long long int ULL;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<LL> VLL;
typedef vector<VLL> VVLL;
typedef vector<ULL> VULL;
typedef vector<VULL> VVULL;
typedef vector<double> VD;
typedef vector<VD> VVD;
typedef vector<bool> VB;
typedef vector<VB> VVB;
typedef vector<char> VC;
typedef vector<VC> VVC;
typedef vector<string> VS;
typedef vector<VS> VVS;
typedef pair<int, int> PII;
typedef complex<int> P;
#define PQ(type) priority_queue<type>
// priority queue reverse
#define PQR(type) priority_queue< type, vector<type>, greater<type> >
// }}}
// macros & inline functions {{{
// syntax sugars {{{
#define FOR(i, b, e) for (typeof(e) i = (b); i < (e); ++i)
#define FORI(i, b, e) for (typeof(e) i = (b); i <= (e); ++i)
#define REP(i, n) FOR(i, 0, n)
#define REPI(i, n) FORI(i, 0, n)
#define OPOVER(_op, _type) inline bool operator _op (const _type &t) const
#define ASSIGN_MAX(var, val) ((var) = max((var), (val)))
#define ASSIGN_MIN(var, val) ((var) = min((var), (val)))
// }}}
// conversion {{{
inline int toInt(string s) { int v; istringstream sin(s); sin>>v; return v; }
template<class T> inline string toString(T x) { ostringstream sout; sout<<x; return sout.str(); }
// }}}
// array and STL {{{
#define ARRSIZE(a) ( sizeof(a) / sizeof(a[0]) )
#define ZERO(a, v) ( assert(v == 0 || v == -1), memset(a, v, sizeof(a)) )
#define F first
#define S second
#define MP(a, b) make_pair(a, b)
#define SIZE(a) ((LL)a.size())
#define PB(e) push_back(e)
#define SORT(v) sort((v).begin(), (v).end())
#define RSORT(v) sort((v).rbegin(), (v).rend())
#define ALL(a) (a).begin(), (a).end()
#define RALL(a) (a).rbegin(), (a).rend()
#define EACH(c, it) for(typeof((c).begin()) it=(c).begin(); it!=(c).end(); ++it)
#define REACH(c, it) for(typeof((c).rbegin()) it=(c).rbegin(); it!=(c).rend(); ++it)
#define EXIST(s, e) ((s).find(e) != (s).end())
// }}}
// bit manipulation {{{
// singed integers are not for bitwise operations, specifically arithmetic shifts ('>>', and maybe not good for '<<' too)
#define IS_UNSIGNED(n) (!numeric_limits<typeof(n)>::is_signed)
#define BIT(n) (assert(IS_UNSIGNED(n)), assert(n < 64), (1ULL << (n)))
#define BITOF(n, m) (assert(IS_UNSIGNED(n)), assert(m < 64), ((ULL)(n) >> (m) & 1))
inline int BITS_COUNT(ULL b) { int c = 0; while(b != 0) { c += (b & 1); b >>= 1; } return c; }
inline int MSB(ULL b) { int c = 0; while(b != 0) { ++c; b >>= 1; } return c-1; }
inline int MAKE_MASK(ULL upper, ULL lower) { assert(lower < 64 && upper < 64 && lower <= upper); return (BIT(upper) - 1) ^ (BIT(lower) - 1); }
// }}}
// for readable code {{{
#define EVEN(n) (n % 2 == 0)
#define ODD(n) (!EVEN(n))
// }}}
// debug {{{
#define arrsz(a) ( sizeof(a) / sizeof(a[0]) )
#define dprt(fmt, ...) if (opt_debug) { fprintf(stderr, fmt, ##__VA_ARGS__); }
#define darr(a) if (opt_debug) { copy( (a), (a) + arrsz(a), ostream_iterator<int>(cerr, " ") ); cerr << endl; }
#define darr_range(a, f, t) if (opt_debug) { copy( (a) + (f), (a) + (t), ostream_iterator<int>(cerr, " ") ); cerr << endl; }
#define dvec(v) if (opt_debug) { copy( ALL(v), ostream_iterator<int>(cerr, " ") ); cerr << endl; }
#define darr2(a) if (opt_debug) { FOR(__i, 0, (arrsz(a))){ darr( (a)[__i] ); } }
#define WAIT() if (opt_debug) { string _wait_; cerr << "(hit return to continue)" << endl; getline(cin, _wait_); }
#define dump(x) if (opt_debug) { cerr << " [L" << __LINE__ << "] " << #x << " = " << (x) << endl; }
// dump vector elements in [s, e)
#define dumpv(v, s, e) if (opt_debug) { cerr << " [L" << __LINE__ << "] " << #v << " = "; FOR(__i, s, e) { cerr << v[__i] << "\t"; } cerr << endl; }
#define dumpl(x) if (opt_debug) { cerr << " [L" << __LINE__ << "] " << #x << endl << (x) << endl; }
#define dumpf() if (opt_debug) { cerr << __PRETTY_FUNCTION__ << endl; }
#define where() if (opt_debug) { cerr << __FILE__ << ": " << __PRETTY_FUNCTION__ << " [L: " << __LINE__ << "]" << endl; }
#define show_bits(b, s) if(opt_debug) { REP(i, s) { cerr << BITOF(b, s-1-i); if(i%4 == 3) cerr << ' '; } cerr << endl; }

// ostreams {{{
// complex
template<typename T> ostream& operator<<(ostream& s, const complex<T>& d) {return s << "(" << d.real() << ", " << d.imag() << ")";}

// pair
template<typename T1, typename T2> ostream& operator<<(ostream& s, const pair<T1, T2>& d) {return s << "(" << d.first << ", " << d.second << ")";}

// vector
template<typename T> ostream& operator<<(ostream& s, const vector<T>& d) {
	int len = d.size();
	REP (i, len) {
		s << d[i]; if (i < len - 1) s << "\t";
	}
	return s;
}

// 2 dimentional vector
template<typename T> ostream& operator<<(ostream& s, const vector< vector<T> >& d) {
	int len = d.size();
	REP (i, len) {
		s << d[i] << endl;
	}
	return s;
}

// map
template<typename T1, typename T2> ostream& operator<<(ostream& s, const map<T1, T2>& m) {
	s << "{" << endl;
	for (typeof(m.begin()) itr = m.begin(); itr != m.end(); ++itr) {
		s << "\t" << (*itr).first << " : " << (*itr).second << endl;
	}
	s << "}" << endl;
	return s;
}
// }}}
// }}}
// }}}
// time {{{
inline double now(){ struct timeval tv; gettimeofday(&tv, NULL); return (static_cast<double>(tv.tv_sec) + static_cast<double>(tv.tv_usec) * 1e-6); }
// }}}
// string manipulation {{{
inline VS split(string s, char delimiter) { VS v; string t; REP(i, s.length()) { if(s[i] == delimiter) v.PB(t), t = ""; else t += s[i]; } v.PB(t); return v; }
inline string join(VS s, string j) { string t; REP(i, s.size()) { t += s[i] + j; } return t; }
// }}}
// geometry {{{
#define Y real()
#define X imag()
// }}}
// 2 dimentional array {{{
enum { UP, RIGHT, DOWN, LEFT, UP_RIGHT, DOWN_RIGHT, DOWN_LEFT, UP_LEFT };
P dydx4[4] = { P(-1, 0), P(0, 1), P(1, 0), P(0, -1) };
P dydx8[8] = { P(-1, 0), P(0, 1), P(1, 0), P(0, -1), P(-1, 1), P(1, 1), P(1, -1), P(-1, -1) };
bool in_field(int H, int W, P p) {
	return (0 <= p.Y && p.Y < H) && (0 <= p.X && p.X < W);
}
// }}}
// input and output {{{
inline void input(string filename) {
	freopen(filename.c_str(), "r", stdin);
}
inline void output(string filename) {
	freopen(filename.c_str(), "w", stdout);
}
// }}}
// }}}

// Header under development {{{

int LCM(int a, int b) {
	// FIXME
	return a * b;
}

// Fraction class {{{
// ref: http://martin-thoma.com/fractions-in-cpp/
class Fraction {
	public:
		ULL numerator;
		ULL denominator;
		Fraction(ULL _numerator, ULL _denominator) {
			assert(_denominator > 0);
			numerator = _numerator;
			denominator = _denominator;
		};

		Fraction operator*(const ULL rhs) {
			return Fraction(this->numerator * rhs, this->denominator);
		};

		Fraction operator*(const Fraction& rhs) {
			return Fraction(this->numerator * rhs.numerator, this->denominator * rhs.denominator);
		}

		Fraction operator+(const Fraction& rhs) {
			ULL lcm = LCM(this->denominator, rhs.denominator);
			ULL numer_lhs = this->numerator * (this->denominator / lcm);
			ULL numer_rhs = rhs.numerator * (rhs.numerator / lcm);
			return Fraction(numer_lhs + numer_rhs, lcm);
		}

		Fraction& operator+=(const Fraction& rhs) {
			Fraction result = (*this) + rhs;
			this->numerator = result.numerator;
			this->denominator = result.denominator;
			return *this;
		}
};

std::ostream& operator<<(std::ostream &s, const Fraction &a) {
	if (a.denominator == 1) {
		s << a.numerator;
	} else {
		s << a.numerator << "/" << a.denominator;
	}
	return s;
}

// }}}

// }}}

bool opt_debug = false;

class GeometryUtil {
	public:
		bool eql(double a, double b) { return abs(a - b) < EPS; }
		bool lt(double a, double b) { return b - a >= EPS; }
		bool lte(double a, double b) { return lt(a, b) || eql(a, b); }
		bool gt(double a, double b) { return !lte(a, b); }
		bool gte(double a, double b) { return !lt(a, b); }
		bool eql(P a, P b) { return eql(a.Y, b.Y) && eql(a.X, b.X); }
		GeometryUtil() {
		}
};

GeometryUtil geo = GeometryUtil();

template<typename T>
class Vector3D {
	public:
		T x, y, z;
		Vector3D(T _x, T _y, T _z): x(_x), y(_y), z(_z) {
		}

		T abs() {
			return sqrt(pow(x, 2) + pow(y, 2) + pow(z, 2));
		}

		T dot(Vector3D<T> rhs) {
			return x * rhs.x + y * rhs.y + z * rhs.z;
		}

		Vector3D<T> cross(Vector3D<T> rhs) {
			return Vector3D(y*rhs.z - z*rhs.y, z*rhs.x - x*rhs.z, x*rhs.y - y*rhs.x);
		}

		// check if this Vector3D (as a point) is on a line (a-b)
		bool is_upon(const Vector3D<T> a, const Vector3D<T> b) const {
			dump((b-a).cross(b-(*this)).abs());
			dump(geo.eql((b-a).cross(b-(*this)).abs(), 0));
			dump((b-a).dot((*this)-a));
			dump(geo.gt( (b-a).dot((*this)-a), 0 ));
			dump((a-b).dot((*this)-b));
			dump(geo.gt( (a-b).dot((*this)-b), 0 ));

			return geo.eql( (b-a).cross(b-(*this)).abs(), 0 ) &&
				geo.gt( (b-a).dot((*this)-a), 0 ) &&
				geo.gt( (a-b).dot((*this)-b), 0 );
		}

		// Add vector
		Vector3D<T> operator+(const Vector3D<T>& rhs) const {
			return Vector3D<T>(x + rhs.x, y + rhs.y, z + rhs.z);
		}

		// Subtract vecrtor
		Vector3D<T> operator-(const Vector3D<T>& rhs) const {
			return Vector3D<T>(x - rhs.x, y - rhs.y, z - rhs.z);
		}

		// Multiply by scala value
		template<typename Scala>
		Vector3D<T> operator*(const Scala rhs) const {
			return Vector3D<T>(x * rhs, y * rhs, z * rhs);
		}
};
template<typename T>
ostream& operator<<(ostream& out, const Vector3D<T>& v) {
	return out << "(" << v.x << ", " << v.y << ", " << v.z << ")";
}

template<typename T>
class Sphere {
	public:
		T x, y, z, r;
		Sphere(T _x, T _y, T _z, T _r) : x(_x), y(_y), z(_z), r(_r) {
		}

		// distance of the centers of spheres
		T distance(const Sphere& rhs) const {
			// move two spheres so that the center of (*this) comes to the origin
			Sphere _r(rhs.x - x, rhs.y - y, rhs.z - z, rhs.r);
			return Vector3D<T>(_r.x, _r.y, _r.z).abs();
		}

		// check if this sphere is completely inside of rhs
		bool is_inside_of(const Sphere& rhs) const {
			return geo.lt(distance(rhs) + r, rhs.r);
		}

		// check if this sphere is completely outside of rhs
		bool is_outside_of(const Sphere& rhs) const {
			return geo.gt(distance(rhs) - r, rhs.r);
		}

		// check if this sphere is touching with rhs
		bool is_touching_with(const Sphere& rhs) const {
			return
				geo.eql(distance(rhs), r + rhs.r) ||
				((*this).is_inside_of(rhs) && geo.eql(distance(rhs) + r, rhs.r)) ||
				(rhs.is_inside_of((*this)) && geo.eql(distance(rhs) + rhs.r, r));
		}

		bool is_overlapping_with(const Sphere& rhs) const {
			return !is_inside_of(rhs) && !is_outside_of(rhs) && !is_touching_with(rhs);
		}
};
template<typename T>
ostream& operator<<(ostream& out, const Sphere<T>& s) {
	return out << "(" << s.x << ", " << s.y << ", " << s.z << ", " << s.r << ")";
}

class UnionFindTree {
	int n;
	VI parent;
	public:
		UnionFindTree(int _n): n(_n) {
			parent = VI(n);
			REP (i, n) {
				parent[i] = i;
			}
		}

		int group(int x) {
			if (parent[x] == x) {
				return x;
			} else {
				return parent[x] = group(parent[x]);
			}
		}

		bool united(int x, int y) {
			return group(x) == group(y);
		}

		void unite(int x, int y) {
			x = group(x);
			y = group(y);
			parent[x] = y;
		}
};

int main(int argc, char** argv) {
	std::ios_base::sync_with_stdio(false);
	// set options {{{
	int __c;
	while ( (__c = getopt(argc, argv, "d")) != -1 ) {
		switch (__c) {
			case 'd':
				opt_debug = true;
				break;
			default:
				abort();
		}
	}
	// }}}

	// opt_debug = true;
	// input("./inputs/0.txt");
	// output("./outputs/0.txt");

	int n;
	while (cin >> n, n) {
		dump(n);
		vector< Sphere<double> > cells;
		REP (i, n) {
			double x, y, z, r; cin >> x >> y >> z >> r;
			cells.PB(Sphere<double>(x,y,z,r));
		}
		VVD costs(n, VD(n, INF));
		REP (i, n) {
			REP (j, n) {
				if (i == j) { costs[i][j] = costs[j][i] = 0; continue; }
				if (cells[i].is_touching_with(cells[j]) || cells[i].is_overlapping_with(cells[j])) {
					costs[i][j] = costs[j][i] = 0;
				} else if (cells[i].is_inside_of(cells[j])) {
					costs[i][j] = costs[j][i] = cells[j].r - cells[i].distance(cells[j]) - cells[i].r;
				} else if (cells[j].is_inside_of(cells[i])) {
					costs[i][j] = costs[j][i] = cells[i].r - cells[i].distance(cells[j]) - cells[j].r;
				} else {
					// outside of each other
					costs[i][j] = costs[j][i] = cells[i].distance(cells[j]) - cells[i].r - cells[j].r;
				}
			}
		}

		REP (i, n) {
			REP (j, n) {
				if (i == j) { continue; }
				if (cells[i].is_inside_of(cells[j])) {
					costs[i][j] = costs[j][i] = 0;
				}
			}
		}

		dumpl(costs);

		double ans = 0;
		UnionFindTree ut(n);
		typedef pair<double, PII> PDPII;
		vector<PDPII> edges; // (cost, (from, to))
		REP (i, n) {
			FOR (j, i+1, n) {
				edges.PB(MP(costs[i][j], MP(i, j)));
			}
		}
		SORT(edges);

		REP (i, edges.size()) {
			double cost = edges[i].F;
			int from = edges[i].S.F;
			int to = edges[i].S.S;
			if (ut.united(from, to)) { continue; }
			ut.unite(from, to);
			dump(from);
			dump(to);
			dump(cost);
			ans += cost;
		}
		printf("%.3lf\n", ans);
	}

	return 0;
}

// vim: foldmethod=marker

Measured memory_bytes: 1588