#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
const int MAXN = 1e4 + 10;//拿来开存边的数量的结构体 题目N<100 所以最多开到N*N也就是1e4就够了
const int maxn = 110;//用于开存点的数量结构体
struct node {//用于储存输入的点
double x, y, z, r;
}ball[maxn];
struct P {//用于储存转换后的边 代表点 x 到 y 的距离
int x, y;
double dis;
bool friend operator<(const P& a, const P& b) {
return a.dis < b.dis;
}
}p[MAXN];
int parent[MAXN];
int get(int x) {
return parent[x] == x ? x : parent[x] = get(parent[x]);
}
void merge(int x, int y) {
parent[get(x)] = get(y);
}
double distan(node a, node b) {//用于求两个点的距离
double dis = sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) + (a.z - b.z) * (a.z - b.z));
if (dis <= a.r + b.r) return 0;//如果两个球相交或者相切 那么他们的距离就是0
else return (dis - a.r - b.r);
}
int all = 1;//用于表示转换之后边的数量
void change(int x, int y, double dis) {//把两个点转换为边的表现形式的函数
p[all].x = x;
p[all].y = y;
p[all++].dis = dis;
}
int main(void) {
int N;
while (scanf("%d", &N), N) {
all = 1;
for (int i = 1; i <= N; i++) parent[i] = i;
for (int i = 1; i <= N; i++) {
scanf("%lf%lf%lf%lf", &ball[i].x, &ball[i].y, &ball[i].z, &ball[i].r);
}
for (int i = 1; i <= N; i++) {
for (int j = i + 1; j <= N; j++) {
double dis = distan(ball[i], ball[j]);//遍历第一个点到第二、三……N个点 然后第二个点到第三、四……N个点…… 第N-1到第N个点的边
change(i, j, dis);//把第i个点到第j个点距离为dis的数据存到p结构体中
}
}
all--;
sort(p + 1, p + all+1);//按照距离从小到大排序
int cnt = 0;
double ans = 0;
for (int i = 1; i <= all; i++) {
int fx = get(p[i].x), fy = get(p[i].y);
if (fx == fy) continue;
merge(fx, fy);
cnt++;
ans += p[i].dis;
if (cnt == N - 1) break;
}
printf("%.3lf\n", ans);
}
return 0;
}