/*
 * Copyright (c) 2004 Kamo Hiroyasu
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 *  A solution of "Building Space Station"
 *   (Prim's algorithm)
 *   Author: Kamo Hiroyasu <wd@ics.nara-wu.ac.jp>
 */

#include <limits.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef	MAXNBALLS
#define MAXNBALLS	1000
#endif

#define hypot3(x,y,z)	hypot((x), hypot((y), (z)))
#define getballs(b,n)	fgetballs((b), (n), stdin)

struct point {
	double		x, y, z;
};

struct ball {
	struct point	center;
	double		radius;
};

struct joint {
	double		length;
	ssize_t		already, not_yet;
};

size_t		fgetballs(struct ball *, size_t, FILE *);
double		ball_distance(const struct ball *, const struct ball *);
double		total_length(const struct ball *, size_t);

size_t
fgetballs(struct ball *balls, size_t n_max, FILE *fp)
{
	size_t		i, n;
	double		x, y, z, r;

	if (fscanf(fp, "%zu", &n) != 1 || n > n_max) {
		return 0;
	}
	for (i = 0; i < n; i ++) {
		if (fscanf(fp, "%lf%lf%lf%lf", &x, &y, &z, &r) != 4) {
			return 0;
		}
		if (r < 0) {
			return 0;
		}
		balls[i].center.x = x;
		balls[i].center.y = y;
		balls[i].center.z = z;
		balls[i].radius = r;
	}
	return n;
}

double
ball_distance(const struct ball *b1, const struct ball *b2)
{
	double		d;

	d = hypot3(b1->center.x - b2->center.x, b1->center.y - b2->center.y,
		   b1->center.z - b2->center.z)
		- (b1->radius + b2->radius);
	return d >= 0 ? d : 0;
}

double
total_length(const struct ball *balls, size_t num)
{
	double		w_total = 0;
	double		w, w_min;
	struct joint	*set;
	size_t		i, i_min, n;
	ssize_t		u, v;

	set = malloc(num * sizeof(struct joint));
	for (i = 0; i < num; i ++) {
		set[i].length = HUGE_VAL;
 		set[i].already = -1;
		set[i].not_yet = i;
	}
	i_min = 0;
	for (n = num; -- n > 0;) {
		u = set[i_min].not_yet;
		set[i_min] = set[n];
		w_min = HUGE_VAL;
		for (i = 0; i < n; i ++) {
			v = set[i].not_yet;
			w = ball_distance(&balls[u], &balls[v]);
			if (w < set[i].length) {
				set[i].already = u;
				set[i].length = w;
			}
			if (set[i].length < w_min) {
				i_min = i;
				w_min = set[i].length;
			}
		}
		w_total += w_min;
	}
	free(set);
	return w_total;
}

int
main(int argc, char *argv[])
{
	size_t			n;
	double			w;
	static struct ball	balls[MAXNBALLS];

	switch (argc) {
	case 2:
		if (freopen(argv[1], "r", stdin) == NULL) {
			perror(argv[1]);
			return 1;
		}
	case 1:
		break;
	default:
		fprintf(stderr, "%s: too many arguments\n", argv[0]);
		return 1;
	}
	while ((n = getballs(balls, MAXNBALLS)) > 0) {
		w = total_length(balls, n);
		printf("%.3f\n", w);
	}
	return 0;
}
