import std.stdio;
import std.array;
import std.conv;
import std.string;
import std.algorithm;
import std.typecons;
import std.math;


class UnionFind
{
	int[] data;

	this() {
	}

	this(int x) {
		data = new int[](x);
		data[] = -1;
	}

	bool unionSet(int x, int y)
	{
		x = root(x); y=root(y);
		if(x != y)
		{
			if(data[y] < data[x]) swap(x, y);
			data[x] += data[y]; data[y] = x;
		}
		return x != y;
	}
	
	int root(int x)
	{
		if( data[x] < 0 ) return x;
		return data[x]=root(data[x]);
	}
};
	

alias Tuple!(double, "x", double, "y", double, "z") P3;
alias Tuple!(P3, "p", double, "r") Sphere;
alias Tuple!(int, "src", int, "dst", double, "cost") Edge;

string[] inputs;

double dist(Sphere a, Sphere b)
{
	return sqrt((a.p.x-b.p.x)^^2 + (a.p.y-b.p.y)^^2 + (a.p.z-b.p.z)^^2) - (a.r+b.r);
}

bool intersectSS(Sphere a, Sphere b)
{
	return dist(a,b) < 0;
}



double solve(int N, Sphere[] stations) {
	
	int connected = 0;
	double res = 0;

	UnionFind uf = new UnionFind(N);
	Edge[] edges;

	foreach(i; 0..N)
	foreach(j; i+1..N) {
		if(intersectSS(stations[i], stations[j])) {
			uf.unionSet(i,j);
			connected++;
		}
		else edges ~= Edge(i,j,dist(stations[i],stations[j]));
	}

	sort!("a.cost < b.cost")(edges);

	foreach(e; edges) {
		if(connected >= N-1) break;
		if(uf.unionSet(e.src, e.dst)) {
			connected++;
			res += e.cost;
		}
	}

	return res;
}
	

void main()
{
	
	while(true)
	{
		inputs = split(chomp(readln));
		int N = to!int(inputs[0]);
		if(N==0) break;

		Sphere[] stations = new Sphere[](N);
		foreach(i; 0..N) {
			inputs = split(chomp(readln));
			stations[i] = Sphere(P3(to!double(inputs[0]), to!double(inputs[1]), to!double(inputs[2])), to!double(inputs[3]));
		}

		writefln("%.3f", solve(N, stations));
	}
}