using System;
using System.Collections.Generic;
using System.Linq;

namespace AOJ_VOLUME11_1127
{
    class Program
    {
        static void Main(string[] args)
        {
            List<double> anss = new List<double>();
            while (true)
            {
                var N = int.Parse(Console.ReadLine());
                if (N == 0) break;

                Sphere[] spheres = new Sphere[N];
                for (int i = 0; i < N; i++)
                {
                    var xyzr = Console.ReadLine().Split().Select(double.Parse).ToArray();

                    Sphere s = new Sphere();
                    s.x = xyzr[0];
                    s.y = xyzr[1];
                    s.z = xyzr[2];
                    s.r = xyzr[3];
                    spheres[i] = s;
                }

                UnionFind unionFind = new UnionFind(N);

                //エッジ情報の取得
                List<Edge> edges = new List<Edge>();
                for (int i = 0; i < N; i++)
                {
                    for (int j = 0; j < N; j++)
                    {
                        if (i == j) continue;
                        double xd = spheres[i].x - spheres[j].x;
                        double yd = spheres[i].y - spheres[j].y;
                        double zd = spheres[i].z - spheres[j].z;

                        double distance = Math.Pow(xd * xd + yd * yd + zd * zd, 0.5) - spheres[i].r - spheres[j].r;
                        if (distance < 0.00001) unionFind.Unite(i, j);
                        else edges.Add(new Edge() { s = i, t = j, cost = distance });
                    }
                }

                //昇順にソートが必要
                edges = edges.OrderBy(x => x.cost).ToList();


                double ans = 0;   //最小コスト
                foreach (var e in edges)
                {
                    //結合済みでないなら追加
                    if (!unionFind.Same(e.s, e.t))
                    {
                        unionFind.Unite(e.s, e.t);
                        ans += e.cost;
                    }
                }

                anss.Add(ans);
            }

            foreach (var a in anss)
            {
                Console.WriteLine("{0:0.000}",a);
            }
            Console.ReadKey();
        }

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

        struct Edge
        {
            public int s;
            public int t;
            public double cost;
        }

        static int[] ReadInt()
        {
            int[] ret = Console.ReadLine().Split().Select(int.Parse).ToArray();
            return ret;
        }
        static long[] ReadLong()
        {
            long[] ret = Console.ReadLine().Split().Select(long.Parse).ToArray();
            return ret;
        }
    }

    class UnionFind
    {
        int[] par;
        int[] rank;

        public UnionFind(int n)
        {
            init(n);
        }

        void init(int n)
        {
            par = new int[n];
            rank = new int[n];

            for (int i = 0; i < n; i++)
            {
                par[i] = i;
                rank[i] = 0;
            }
        }

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

        public 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]++;
            }

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



Measured memory_bytes: 35648