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

struct Sphere
{
  double x;
  double y;
  double z;
  double r;
}

struct Edge
{
  int left;
  int right;
  double len;
}

class UnionFind
{
  uint[] par;
  this(int n)
  {
    par = new uint[n];
    foreach (i, ref p; par)
    {
      p = cast(uint) i;
    }
  }

  uint Find(uint x)
  {
    if (par[x] == x)
    {
      return x;
    }
    else
    {
      return par[x] = Find(par[x]);
    }
  }

  bool Same(uint x, uint y)
  {
    return Find(x) == Find(y);
  }

  void Union(uint x, uint y)
  {
    x = Find(x);
    y = Find(y);
    if (x == y)
    {
      return;
    }

    par[x] = y;
  }
}

double dist(Sphere left, Sphere right)
{
  return max(0, ((cast(double)(left.x - right.x).pow(2) + (left.y - right.y)
      .pow(2) + (left.z - right.z).pow(2)).sqrt - left.r - right.r));
}

void main()
{
  for (;;)
  {
    int n = readln.chomp.to!int;
    if (n == 0)
    {
      break;
    }
    Sphere[] list;
    foreach (i; 0 .. n)
    {
      auto v = readln.chomp.split(" ").map!(to!double);
      Sphere s;
      s.x = v[0];
      s.y = v[1];
      s.z = v[2];
      s.r = v[3];
      list ~= s;
    }
    Edge[] atoms;
    foreach (i; 0 .. n)
    {
      foreach (j; i + 1 .. n)
      {
        auto left = list[i];
        auto right = list[j];
        Edge edge;
        edge.left = i;
        edge.right = j;
        edge.len = dist(left, right);
        atoms ~= edge;
      }
    }
    auto uf = new UnionFind(n);
    double acm = 0;
    atoms.sort!((a, b) => a.len < b.len);
    foreach (edge; atoms) {
      if (uf.Same(edge.left, edge.right)){
        continue;
      }
      uf.Union(edge.left, edge.right);
      acm += edge.len;
    }
    writefln("%.3f", acm);
  }
}