//include
//------------------------------------------
#include <vector>
#include <list>
#include <map>
#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 <climits>
#include <queue>

using namespace std;

//typedef
//------------------------------------------
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef long long LL;

//container util
//------------------------------------------
#define ALL(a)  (a).begin(),(a).end()
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define MP make_pair
#define SZ(a) int((a).size())
#define EACH(i,c) for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); ++i)
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define SORT(c) sort((c).begin(),(c).end())

//repetition
//------------------------------------------
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n)  FOR(i,0,n)

//constant
//--------------------------------------------
const double EPS = 1e-10;
const double PI  = acos(-1.0);


class UnionFind{
private:
  vector<int> par, rank;
public:
  UnionFind(int n){
	par.assign(n, 0);
	rank.assign(n, 0);
	for(int i=0;i<n;++i)
	  par[i] = i;
  }

  //find root of x
  int find(int x){
	if(par[x] == 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(rank[x] < rank[y])
	  par[x] = y;
	else{
	  par[y] = x;
	  if(rank[x] == rank[y])
		++rank[x];
	}
  }

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

struct Edge{
  int to;
  double cost;

  Edge(int t, double c): to(t), cost(c)
  {}
  bool operator>(const Edge& rhs) const{
	return cost > rhs.cost;
  }
};

double prim(vector< vector<Edge> >& edges){
  const int V = edges.size();
  double res = 0;
  vector<bool> visited(V, false);
  priority_queue<Edge, vector<Edge>, greater<Edge> > pq;

  pq.push(Edge(0,0));
  for(int i=0;i<V;++i){
	Edge edge = pq.top(); pq.pop();
	int v = edge.to;
	if(visited[v]){
	  --i;
	  continue;
	}
	visited[v] = true;
	res += edge.cost;

	for(auto& e:edges[v]){
	  pq.push(e);
	}
  }

  return res;
}

double x[101], y[101], z[101], r[101];
double dist(int i, int j){
  double dx = x[i]-x[j], dy = y[i]-y[j], dz=z[i]-z[j];
  return dx*dx+dy*dy+dz*dz;
}

int main(){
  cin.tie(0);
  ios_base::sync_with_stdio(false);

  int N;
  while(cin >> N && N){
	REP(i,N) cin >> x[i] >> y[i] >> z[i] >> r[i];
	UnionFind uf(N);
	REP(i,N)REP(j,N)
	  if(dist(i,j)<=(r[i]+r[j])*(r[i]+r[j]))
		uf.unite(i,j);
	
	double e[101][101];
	fill((double*)e, (double*)e+101*101, 10000000);
	set<int> root;
	REP(i,N) root.insert(uf.find(i));
	VI node(root.begin(), root.end());

	REP(i,N){
	  e[i][i] = 0;
	  REP(j,N){
	  int ri = uf.find(i), rj = uf.find(j);
	  if(ri != rj)
		e[ri][rj] = e[rj][ri]
		  = min(e[ri][rj], sqrt(dist(i,j)) - r[i] - r[j]);
	  }
	}
	vector< vector<Edge> > edge(SZ(node));
	REP(i,SZ(node)){
	  REP(j,SZ(node)){
		edge[i].PB(Edge(j, e[node[i]][node[j]]));
		edge[j].PB(Edge(i, e[node[j]][node[i]]));
	  }
	}
	cout << fixed << setprecision(3) << prim(edge) << endl;
  }

  return 0;
}

Measured memory_bytes: 2476