#include <set>
#include <map>
#include <list>
#include <queue>
#include <stack>
#include <cmath>
#include <ctype.h>
#include <ctime>
#include <cstdio>
#include <vector>
#include <string>
#include <bitset>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <utility>
#include <numeric>
#include <complex>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <cassert>
#include <iostream>
#include <iterator>
#include <algorithm>

using namespace std;

#define REP(i, x, n) for(int i = x; i < n; i++)
#define rep(i, n) REP(i, 0, n)
#define lengthof(x) (sizeof(x) / sizeof(*(x)))
#define FILL(ptr, value) FILL_((ptr), sizeof(ptr)/sizeof(value), (value))
template <typename T>
void FILL_(void * ptr, size_t size, T value){
  std::fill((T*)ptr, (T*)ptr+size, value);
}
//4方向ベクトル→↑←↓
int dx[] ={1,0,-1,0};
int dy[] ={0,-1,0,1};
int n;//細胞の数

double cost[100][100];
double mincost[100];//集合Xからの辺の最小コスト
bool used[100];
double X[100],Y[100],Z[100],R[100];
#define INF 10000000
double prime(){
  for(int i = 0;i <n;i++){
    mincost[i] = INF;
    used[i] = false;
  }
  mincost[0] = 0;
  double res = 0;
  while(1){
    int v = -1;
    for(int u = 0;u <n;u++){
      if(!used[u]&&(v==-1||mincost[u]<mincost[v]))
	v = u;
    }
    if(v==-1)
      break;
    used[v] = true;
    res +=mincost[v];
    for(int u =0;u <n;u++){
      mincost[u] =min(mincost[u],min(cost[v][u],cost[u][v]));
    }
  }
  return res;
}



int main()
{
  while(cin>>n,n){
    
    for(int i = 0;i < n;i++){
      cin>>X[i]>>Y[i]>>Z[i]>>R[i];
    }
    for(int i = 0;i < n-1;i++){
      for(int j = i+1;j < n;j++){
	double du =(X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j])+(Z[i]-Z[j])*(Z[i]-Z[j]);
	double d =sqrt(du)-(R[i]+R[j]);
	if(d <=0){
	  cost[i][j] = 0;
	  cost[j][i] = 0;
	}else{
	  cost[i][j] = d;
	  cost[j][i] = d;
	}
      }
    }
    printf("%.3lf\n",prime());
  }
  return 0;
}