Problem:
Building a Space Station
You are a member of the space station engineering team,
and are assigned a task in the construction process of the station.
You are expected to write a computer program to complete the task.
The space station is made up with a number of units, called
cells.
All cells are sphere-shaped, but their sizes are not necessarily uniform.
Each cell is fixed at its predetermined position
shortly after the station is successfully put into its orbit.
It is quite strange that two cells may be touching each other,
or even may be overlapping.
In an extreme case, a cell may be totally enclosing another one.
I do not know how such arrangements are possible.
All the cells must be connected,
since crew members should be able to walk
from any cell to any other cell.
They can walk from a cell A to another cell B, if,
(1) A and B are touching each other or overlapping,
(2) A and B are connected by a `corridor',
or (3) there is a cell C such that walking from A to C, and also from B to C
are both possible.
Note that the condition (3) should be interpreted transitively.
You are expected to design a configuration,
namely, which pairs of cells are to be connected with corridors.
There is some freedom in the corridor configuration.
For example, if there are three cells A, B and C,
not touching nor overlapping each other,
at least three plans are possible in order to connect all three cells.
The first is to build corridors A-B and A-C,
the second B-C and B-A, the third C-A and C-B.
The cost of building a corridor is proportional to its length.
Therefore, you should choose a plan with the shortest
total length of the corridors.
You can ignore the width of a corridor.
A corridor is built between points on two cells' surfaces.
It can be made arbitrarily long, but of course the shortest one is chosen.
Even if two corridors A-B and C-D intersect in space, they are
not considered to form a connection path between (for example) A and C.
In other words, you may consider that two corridors never intersect.
Input
The input consists of multiple data sets.
Each data set is given in the following format.
n
x
1
y
1
z
1
r
1
x
2
y
2
z
2
r
2
...
x
n
y
n
z
n
r
n
The first line of a data set contains an integer
n
,
which is the number of cells.
n
is positive, and does not exceed 100.
The following
n
lines are descriptions of cells.
Four values in a line are
x-
,
y-
and
z-
coordinates of
the center, and radius (called
r
in the rest of the problem) of
the sphere, in this order.
Each value is given by a decimal fraction, with
3 digits after the decimal point.
Values are separated by a space character.
Each of
x
,
y
,
z
and
r
is positive
and is less than 100.0.
The end of the input is indicated by a line containing a zero.
Output
For each data set, the shortest total length of the corridors
should be printed, each in a separate line.
The printed values should have 3 digits after the decimal point.
They may not have an error greater than 0.001.
Note that if no corridors ar
...(truncated)

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;

static int bigint = 1e9;
static ll biglong = 1e18;
static ld eps = 1e-9;
#define rep(i,s,n) for(int i=s;i<(int)(n);i++)
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
typedef pair<int, int> pii;
typedef vector<int> vi;


//ーーー入出力
template<typename T>
vector<T> arrayInput(int n) {
    vector<T> a(n);
    for (int i = 0; i < n; i++) cin >> a[i];
    return a;
}
template<typename T>
vector<vector<T>> arrayInput(int h, int w) {
    vector<vector<T>> a(h, vector<T>(w));
    for (int i = 0; i < h; i++) for (int j = 0; j < w; j++) cin >> a[i][j];
    return a;
}

template <typename T>
void arrayPrint(const vector<T>& vec, bool blank = true) {
    for (int i = 0; i < vec.size(); ++i) cout << vec[i] << (blank?" ":"");
    cout << endl;
}
template <typename T>
void arrayPrint(const vector<vector<T>>& mat, bool blank = true) {for (const auto& row : mat) arrayPrint(row, blank);}

template <typename T>
vector<T> csum(vector<T>& input) {
    int n = input.size();
    vector<T> sum(n+1);
    for (int i=1;i<n+1;i++) sum[i] = sum[i-1] + input[i-1];
    return sum;
}
template <typename T>
vector<vector<T>> csum(vector<vector<T>>& input) {
    int h = input.size(), w = input[0].size();
    vector<vector<T>> csum(h+1, vector<T>(w+1));
    for (int i=0;i<h+1;i++) for (int j=0;j<w+1;j++) csum[i][j] = (i==0||j==0) ? 0: csum[i-1][j] + csum[i][j-1] - csum[i-1][j-1] + input[i-1][j-1];
    return csum;
}
//a/bの商
long long floor(long long a, long long b) {
    if (a % b == 0 || a >= 0) return a / b;
    else return -((-a) / b) - 1;
}




void rwfile(){freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);}

struct UF {
    vector<int> par,siz;
    UF(int n) {
        par = vector<int>(n,-1);
        siz = vector<int>(n);
    }
    int root(int x) {
        while (par[x] != -1)x = par[x];
        return x;
    }
    bool same(int a,int b) {
        return root(a) == root(b);
    }
    void unite(int a,int b) {
        int rootA = root(a);
        int rootB = root(b);
        if (rootA == rootB) return;
        if (siz[rootA] < siz[rootB]) {
            par[rootA] = rootB;
            siz[rootB] += siz[rootA];

        }else {
            par[rootB] = rootA;
            siz[rootA] += siz[rootB];

        }

    }
};

int main() {
    cout << fixed << setprecision(3);
    while (true) {
        int n;cin >> n;
        if (n==0)break;
        vector<ld>x(n),y(n),z(n),r(n);
        rep(i,0,n) cin >> x[i] >> y[i] >> z[i] >> r[i];
        UF uf(n);
        priority_queue<tuple<ld,int,int>,vector<tuple<ld,int,int>>,greater<tuple<ld,int,int>>> pq;
        rep(i,0,n) {
            // cerr << x[i] << " " << y[i] << " " << z[i] <<" " << r[i] << endl;
            rep(j,i+1,n) {
                ld xy = (x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j]) * (y[i] - y[j]);
                ld xyz = sqrt(sqrt(xy)*sqrt(xy) + (z[i]-z[j]) * (z[i]-z[j]));
                // cerr << i <<" " << j << " " << xyz << " " << (r[i]+r[j]) << endl;
                if (xyz -(r[i]+r[j])< eps) {
                    uf.unite(i,j);
                }else {
                    pq.push(make_tuple(xyz-(r[i]+r[j]), i, j));
                }
            }
        }

        ld sum = 0;
        while (!pq.empty()) {
            auto e = pq.top(); pq.pop();
            ld cost = get<0>(e);
            int a = get<1>(e);
            int b = get<2>(e);
            if (!uf.same(a,b)) {
                uf.unite(a,b);
                sum += cost;
            }
        }

        cout << sum << endl;
    }


}
accuracy: 1
time_ms: 10
memory_kb: 3728
final_rank: 8

code_snippet: #include <bits/stdc++.h>

#pragma GCC target("avx2")
#ifndef LOCAL
#pragma GCC optimize("O3")
#endif
#pragma GCC optimize("unroll-loops")

#ifdef ONLINE_JUDGE
#include <boost/multiprecision/cpp_int.hpp>
#include <atcoder/all>
#endif
#ifdef LOCAL
#define GLIBCXX_DEBUG
#else
#define endl "\n"
#endif
using namespace std;using ll=long long;using ull=unsigned long long;using dl=long double;
#define rep(i,n) for(ll i=0; i<(n); i++)
#define rrep(i,n) for(ll i=1; i<=(n); i++)
#define drep(i,n) for(ll i=(n)-1; i>=0; i--)
#define xfor(i,s,e) for(ll i=(s); i<(e); i++)
#define rxfor(i,s,e) for(ll i=(s); i<=(e); i++)
#define dfor(i,s,e) for(ll i=(s)-1; i>=(e); i--)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
#define chmax(x,y) x = max((x),(y))
#define chmin(x,y) x = min((x),(y))
#define popcnt(s) ll(__popcount<ull>(uint64_t(s)))
template<typename T>istream&operator>>(istream&is,const pair<T,T>&v){is>>v.first>>v.second;return is;}
template<typename T>istream&operator>>(istream&is,const vector<T>&v){for(auto&in:v)is>>in;return is;}
template<typename T, typename U>ostream&operator<<(ostream&os,const pair<T,U>&v){os<<v.first<<" "<<v.second;return os;}
template<typename T>ostream&operator<<(ostream&os,const vector<T>&v){for(auto&in:v)os<<in<<' ';return os;}
template<typename T>ostream&operator<<(ostream&os,const vector<vector<T>>&v){for(auto&in:v)os<<in<<endl;return os;}
ll modpow(ll a, ll b, ll mod) {ll res = 1;while (b > 0) {if (b & 1) res = (res * a) % mod;a = (a * a) % mod;b >>= 1;}return res;}
ll powl(ll a, ll b) {ll res = 1;while (b > 0) {if (b & 1) res = (res * a);a = (a * a);b >>= 1;}return res;}
#define pow2(a) (a)*(a)
/*MOD MUST BE A PRIME NUMBER!!*/ll moddiv(const ll a, const ll b, const ll mod) {ll modinv = modpow(b, mod-2, mod);return (a * modinv) % mod;}
const ll INF = 2e15;
ll nC2(const ll i){return i>2?i*(i-1)/2:0;}ll nC3(const ll i){return i>3?i*(i-1)*(i-2)/6:0;}ll nC4(const ll i){return i>4?i*(i-1)*(i-2)*(i-3)/24:0;}ll nC5(const ll i){return i>5?i*(i-1)*(i-2)*(i-3)*(i-4)/120:0;}ll nC6(const ll i){return i>6?i*(i-1)*(i-2)*(i-3)*(i-4)*(i-5)/720:0;}
template<typename T>void warshall_floyd(vector<vector<T>>& dist) {const ull n = dist.size();rep(k, n) rep(i, n) rep(j, n) {dist[i][j] = min(dist[i][j],dist[i][k] + dist[k][j]);}}
#define YES {cout<<"Yes\n";return;}
#define NO {cout<<"No\n";return;}
#define yn YES else NO
#ifdef ONLINE_JUDGE
using lll = boost::multiprecision::cpp_int;
//using lll = boost::multiprecision::int128_t;
using namespace atcoder;
//using mint = modint1000000007;
using mint = modint998244353;
//using mint = modint; // custom mod
//atcoder::modint::set_mod(m);
// DSU == UnionFind
#endif
#define vc vector
using P = pair<ll, ll>;using vl = vc<ll>;using vb=vc<bool>;using vs=vc<string>;using vvl=vc<vl>;using vp=vc<P>;
#define pq priority_queue
template<typename T>void cs(vector<T>&v){xfor(i,1,v.size())v[i]+=v[i-1];}

vl dx = {-1, 1, 0, 0, -1, 1, -1, 1};
vl dy = {0, 0, 1, -1, -1, -1, 1, 1};

const ll mod = 998244353;

/// @brief Union-Find 木
/// @note 1.4 高速化 + 省メモリ化
/// @see https://zenn.dev/reputeless/books/standard-cpp-for-competitive-programming/viewer/union-find
class UnionFind
{
public:

	UnionFind() = default;

	/// @brief Union-Find 木を構築します。
	/// @param n 要素数
	explicit UnionFind(size_t n)
		: m_parentsOrSize(n, -1) {}

	/// @brief 頂点 i の root のインデックスを返します。
	/// @param i 調べる頂点のインデックス
	/// @return 頂点 i の root のインデックス
	int find(int i)
	{
		if (m_parentsOrSize[i] < 0)
		{
			return i;
		}

		// 経路圧縮
		return (m_parentsOrSize[i] = find(m_parentsOrSize[i]));
	}

	/// @brief a のグループと b のグループを統合します。
	/// @param a 一方のインデックス
	/// @param b 他方のインデックス
	void merge(int a, int b)
	{
		a = find(a);
		b = find(b);

		if (a != b)
		{
			// union by size (小さいほうが子になる）
			if (-m_parentsOrSize[a] < -m_parentsOrSize[b])
			{
				std::swap(a, b);
			}

			m_parentsOrSize[a] += m_parentsOrSize[b];
			m_parentsOrSize[b] = a;
		}
	}

	/// @brief a と b が同じグループに属すかを返します。
	/// @param a 一方のインデックス
	/// @param b 他方のインデックス
	/// @return a と b が同じグループに属す場合 true, それ以外の場合は false
	bool connected(int a, int b)
	{
		return (find(a) == find(b));
	}

	/// @brief i が属するグループの要素数を返します。
	/// @param i インデックス
	/// @return i が属するグループの要素数
	int size(int i)
	{
		return -m_parentsOrSize[find(i)];
	}

private:

	// m_parentsOrSize[i] は i の 親,
	// ただし root の場合は (-1 * そのグループに属する要素数)
	std::vector<int> m_parentsOrSize;
};

bool is_finished = false;

void solve() {
    ll N; cin >> N;
    if (N == 0) {
        is_finished = true;
        return;
    }
    vc<double> X(N), Y(N), Z(N), r(N);
    rep(i, N) cin >> X[i] >> Y[i] >> Z[i] >> r[i];

    auto dist = [&](ll v1, ll v2){
        return sqrt(pow2(X[v1]-X[v2])+pow2(Y[v1]-Y[v2])+pow2(Z[v1]-Z[v2]));
    };

    pq<tuple<double,ll,ll>, vector<tuple<double,ll,ll>>, greater<>> q; // cost, vert_A, vert_B (A < B)

    UnionFind uf(N);

    rep(i, N) {
        xfor(j, i+1, N) {
            double d = dist(i,j)-r[i]-r[j];
            if (d <= 0) {
                uf.merge(i, j);
            } else {
                q.emplace(d,i,j);
            }
        }
    }

    auto ok = [&](){
        bool OK = true;
        rep(i, N) rep(j, N) if (!uf.connected(i,j)) OK = false;
        return OK;
    };
    double cost = 0;
    while (!ok() && !q.empty()) {
        auto [now_cost, a, b] = q.top(); q.pop();
        if (uf.connected(a,b))continue;
        cost += now_cost;
        uf.merge(a, b);
    }

    cout << cost << endl;
}

int main() {
    ios_base::sync_with_stdio(false);
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    cout << fixed << setprecision(3);

    ll n = 1;
    //cin >> n;
    while (!is_finished) {
        solve();
    }
}
accuracy: 1
time_ms: 40
memory_kb: 4076
final_rank: 19

code_snippet: #ifndef ONLINE_JUDGE
#define _GLIBCXX_DEBUG
#endif

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using P = pair<int,int>;
//https://boostjp.github.io/tips/multiprec-int.html

#define YES cout<<"Yes"<<endl
#define NO cout<<"No"<<endl
#define YN {cout<<"Yes"<<endl;}else{cout<<"No"<<endl;}// if(a==b)YN;
#define NO2 cout<<-1<<endl

#define rep(i, n) for (int i = 0; i < (int)(n); ++i)
#define rrep(i, n) for (int i=int(n)-1; i>=0; --i)
#define all(a) a.begin(),a.end()
#define rall(a) a.rbegin(),a.rend()

struct UnionFind {
    vector<int> parent, size;

    UnionFind(int n) : parent(n, -1), size(n, 1) {
    	//初期操作　def __init__ のようなもの
    }

    int root(int x) {
        if(parent[x] == -1) return x;
        return parent[x] = root(parent[x]);
    }

    bool isSame(int x, int y) {
        return root(x) == root(y);
    }

    void unite(int x, int y) {
        int rootX = root(x);
        int rootY = root(y);
        if (rootX == rootY) return;

        if (size[rootX] < size[rootY]) swap(rootX, rootY);
        
        parent[rootY] = rootX;
        size[rootX] += size[rootY]; 
    }
    
    int leaves(int x) {
        return size[root(x)];
    }
};

using T = tuple<double, int, int>;
void solve(int N) {
    UnionFind uf(N);
    vector<double> X(N), Y(N), Z(N), R(N);
    rep(i,N) {
        cin >> X[i] >> Y[i] >> Z[i] >> R[i];
    }
    double ans = 0.0;
    //priority_queue<T, vector<T>, greater<T>> pq;
    vector<T> edges;
    rep(i,N) {
        for (int j=i+1; j<N; ++j) {
            //double dist = hypot(X[i]-X[j], Y[i]-Y[j], Z[i]-Z[j]) - (R[i]+R[j]);
            double dx = X[i]-X[j];
            double dy = Y[i]-Y[j];
            double dz = Z[i]-Z[j];
            double dist = sqrt(dx*dx+dy*dy+dz*dz)-(R[i]+R[j]);
            if (dist <= 0) {
                uf.unite(i,j);
                continue;
            }
            edges.emplace_back(make_tuple(dist, i, j));
        }
    }
    sort(all(edges));

    for (const auto &edge : edges) {
        if (uf.leaves(0) == N) break;
        auto [cost, u, v] = edge;
        //pq.pop();
        if (uf.isSame(u,v)) continue;
        ans += cost;
        uf.unite(u,v);
    }
    cout << fixed << setprecision(3) << ans << endl;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    while(true) {
        int N;
        cin>>N;
        if (N == 0) return 0;
        solve(N);
    }
}
accuracy: 1
time_ms: 60
memory_kb: 4096
final_rank: 20

code_snippet: #include <bits/stdc++.h>
using namespace std;
#if __has_include(<atcoder/all>)
#include <atcoder/math>
using namespace atcoder;
#endif

using ll = long long;
using vi = vector<int>;
using vvi = vector<vector<int>>;
using vvvi = vector<vector<vector<int>>>;
using vll = vector<ll>;
using vvll = vector<vector<ll>>;
using vvvll = vector<vector<vector<ll>>>;
using vd = vector<double>;
using vvd = vector<vector<double>>;
using vstr = vector<string>;
using vchr = vector<char>;
using pii = pair<int,int>;
using pll = pair<long long, long long>;
using Graph = vector<vector<int>>;
const int dx[8] = {1, 0, -1, 0, 1, 1, -1, -1};
const int dy[8] = {0, 1, 0, -1, 1, -1, 1, -1};

#define rep(i, a, b) for(int i = (int)a; i < (int)b; i++)
#define REP(i, a, b) for (int i = (int)a; i <= (int)b; i++)
#define all(v) v.begin(), v.end()
#define rall(v) v.rbegin(), v.rend()
#define YESNO(flag) cout << (flag ? "Yes" : "No") << "\n"
#define spa " "

const int inf = 1070000000;
const long long INF = 4500000000000000000;
const long long MOD = 998244353;
//const long long MOD = 1000000007;
const double pi = 3.141592653589793238;
const string ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string abc = "abcdefghijklmnopqrstuvwxyz";

template<class T> inline bool chmin(T& a, T b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template<class T> inline bool chmax(T& a, T b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}

//xのn乗
ll llpow(ll x, ll n) {
    ll ans = 1;
    while(n > 0) {
        if(n & 1) ans *= x;
        x *= x;
        n >>= 1; 
    }
    return ans;
}
ll modpow(ll x, ll n, ll mod) {
    ll ans = 1;
    while(n > 0) {
        if(n & 1) ans = ans * x % mod;
        x = x * x % mod;
        n >>= 1;
    }
    return ans;
}
//mod pでのaの逆元
ll inverse(ll a, ll p) {
    return modpow(a, p-2, p);
}
//nの階乗
ll fact(ll n) {
    if(n == 0) return 1;
    else return n * fact(n-1);
}
ll modfact(ll n, ll mod) {
    if(n == 0) return 1;
    else return (n * modfact(n-1, mod)) % mod;
}
//nCr=n!/r!(n-r)! mod p
ll comb(ll n, ll r, ll mod) {
    ll a = modfact(n, mod), b = modfact(r, mod), c = modfact(n-r, mod);
    b = inverse(b, mod); c = inverse(c, mod);
    return (((a*b)%mod)*c)%mod;
}

//1+2+...+n = n(n+1)/2
ll triangle(ll n) {
    ll x = n*(n+1);
    return x/2;
}
//素数判定
bool is_prime(long long x) {
    if(x == 1) return false;
    
    for(long long i = 2; i*i <= x; i++) {
        if(x % i == 0) return false;
    }
    return true;
}

//座標圧縮
vector<int> compress(vector<int> A) {
    vector<int> B = A;

    sort(B.begin(), B.end());
    B.erase(unique(B.begin(), B.end()), B.end());

    vector<int> res(A.size());
    for(int i = 0; i < (int)A.size(); i++) {
        res[i] = lower_bound(B.begin(), B.end(), A[i]) - B.begin();
    }
    return res;
}

//正方形グリッドの右回転
void rotate_right(vector<vector<char>> &S) {
    int N = S.size();
    auto T = S;
    rep(i,0,N) rep(j,0,N) {
        T[i][j] = S[N-1-j][i];
    }
    S = T;
}
//左回転
void rotate_left(vector<vector<char>> &S) {
    int N = S.size();
    auto T = S;
    rep(i,0,N) rep(j,0,N) {
        T[i][j] = S[j][N-1-i];
    }
    S = T;
}

//2点(a,b)と(x,y)の距離
double dist2(ll a, ll b, ll x, ll y) {
    return sqrt((a-x)*(a-x) + (b-y)*(b-y));
}
int man(int a, int b, int x, int y) {
    return abs(a-x) + abs(b-y);
}

//桁数
int digit(ll N) {
    if(N <= 9) return 1;

    return 1 + digit(N / 10);
}
//A進数文字列NをB進数に変換. A,Bは10以下
string base_change(string N, ll A, ll B) {
    ll X = stoll(N), Y = 0;

    ll i = 1;
    while(X != 0) {
        Y += (X % 10) * i;
        i *= A;
        X /= 10;
    }

    X = Y, Y = 0;
    i = 1;
    while(X != 0) {
        Y += (X % B) * i;
        i *= 10;
        X /= B;
    }

    return to_string(Y);
}
//回文判定
bool palin(string S) {
    rep(i,0,S.size()) {
        if(S[i] != S[S.size()-1-i]) return false;
    }
    return true;
}

//hh:mm:ss to second
int convert_to_time(string S) {
    ll h = 10*(S[0]-'0') + (S[1]-'0');
    ll m = 10*(S[3]-'0') + (S[4]-'0');
    ll s = 10*(S[6]-'0') + (S[7]-'0');
    
    return h*3600+m*60+s;
}

//DFS
void dfs(const Graph &G, int v, vector<bool> &seen) { 
    seen[v] = true;
    
    for (auto next_v : G[v]) { 
        if (!seen[next_v]) {
            dfs(G, next_v, seen);
        }
    }
}
void griddfs(const vector<vector<char>> &G, int x, int y, vector<vector<bool>> &seen) {
    int H = G.size(), W = G[0].size();
    seen[x][y] = true;
    
    for (int i = 0; i < 8; i++) { 
        int nx = x + dx[i], ny = y + dy[i];
        if(nx < 0 or nx >= H or ny < 0 or ny >= W) continue;
        if (!seen[nx][ny] and G[nx][ny] != '#') griddfs(G, nx, ny, seen);
    }
}
//BFS
void bfs(const Graph &G, int v, vector<int> &dist) {
    rep(i,0,dist.size()) dist[i] = inf;
    dist[v] = 0;
    queue<int> q;
    q.push(v);
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        for(auto next_u : G[u]) {
            if(dist[next_u] == inf) {
                dist[next_u] = dist[u] + 1;
                q.push(next_u);
            }
        }
    }
}
void gridbfs(const vector<vector<char>> &G, int x, int y, vector<vector<int>> &dist) {
    int H = G.size(), W = G[0].size();
    rep(i,0,H) rep(j,0,W) dist[i][j] = inf;
    dist[x][y] = 0;
    queue<pair<int, int>> q;
    q.push(make_pair(x, y));
    while(!q.empty()) {
        int x = q.front().first, y = q.front().second;
        q.pop();
        for(int i = 0; i < 4; i++) {
            int nx = x + dx[i], ny = y + dy[i];
            if(nx < 0 or nx >= H or ny < 0 or ny >= W) continue;
            if(dist[nx][ny] == inf and G[nx][ny] != '#') {
                dist[nx][ny] = dist[x][y] + 1;
                q.push(make_pair(nx, ny));
            }
        }
    }
}
//ワーシャル・フロイド
vector<vector<ll>> floyd(vector<vector<ll>> G) {
    int N = G.size();
    auto dp = G;
    for (int k = 0; k < N; k++){
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if(dp[i][j] > dp[i][k] + dp[k][j] and dp[i][k] != INF and dp[k][j] != INF) {
                    dp[i][j] = dp[i][k] + dp[k][j];
                }
            }
        }
    }
    return dp;
}

//Union-Find
struct UnionFind {
    vector<int> par; // par[i]:iの親の番号　(例) par[3] = 2 : 3の親が2
    
    UnionFind(int N) : par(N) { //最初は全てが根であるとして初期化
        for(int i = 0; i < N; i++) par[i] = i;
    }
    
    int root(int x) { // データxが属する木の根を再帰で得る：root(x) = {xの木の根}
        if (par[x] == x) return x;
        return par[x] = root(par[x]);
    }
    
    void unite(int x, int y) { // xとyの木を併合
        int rx = root(x); //xの根をrx
        int ry = root(y); //yの根をry
        if (rx == ry) return; //xとyの根が同じ(=同じ木にある)時はそのまま
        par[rx] = ry; //xとyの根が同じでない(=同じ木にない)時：xの根rxをyの根ryにつける
    }
    
    bool same(int x, int y) { // 2つのデータx, yが属する木が同じならtrueを返す
        int rx = root(x);
        int ry = root(y);
        return rx == ry;
    }
};

void solve() {
}

int main() {
    while(1) {
        int N; cin >> N;
        if(N == 0) return 0;

        vd x(N), y(N), z(N), r(N);
        rep(i,0,N) cin >> x[i] >> y[i] >> z[i] >> r[i];

        priority_queue<tuple<double,int,int>, vector<tuple<double,int,int>>, greater<tuple<double,int,int>>> q;
        rep(i,0,N) rep(j,i+1,N) {
            double d = max(sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])+(z[i]-z[j])*(z[i]-z[j])) - (r[i]+r[j]), 0.000);
            q.push(make_tuple(d,i,j));
        }

        UnionFind tree(N);
        double ans = 0;
        while(!q.empty()) {
            double w; int s, t;
            tie(w, s, t) = q.top();
            if(!tree.same(s,t)) {
               ans += w;
                tree.unite(s,t);
            }
            q.pop();
        }
        int dig = digit(floor(ans));
        cout << fixed << setprecision(3) << ans << "\n";
    }

    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3660
final_rank: 5

code_snippet: // メモ
// C++コンテスト用マクロ
#include <bits/stdc++.h>
using namespace std;
using ll = long long; // 整数(long long型)
using ld = long double; // 実数(long double型)
#define rep(i, n) for (ll i = 0; i < (n); i++) // 0~n-1まで
#define nall(a) a.begin(), a.end() // ノーマルオール
#define pb push_back // push_back
#define pob pop_back // pop_back
#define Yes cout << "Yes" << endl // Yes
#define No cout << "No" << endl // No
#ifndef ONLINE_JUDGE
#define _GLIBCXX_DEBUG // 配列外参照時のエラー検出
#endif

struct UnionFind{
    vector<ll> parent;
    UnionFind(ll N){
        parent.resize(N);
        rep(i, N){
            parent[i] = i;
        }
    }

    ll Find(ll i){
        if(parent[i] == i){
            return i;
        }
        else{
            return parent[i] = Find(parent[i]);
        }
    }

    void Unite(ll i, ll j){
        if(Find(i) != Find(j)){
            parent[Find(i)] = parent[Find(j)];
        }
        return;
    }

    bool Same(ll i, ll j){
        return Find(i) == Find(j);
    }
};

int main(){
    vector<ld> ans;
    while(1){
        ll N;
        cin >> N;
        if(N == 0) break;
        vector<ld> dist(N);
        map<ll, tuple<ld, ld, ld>> m;
        rep(i, N){
            ld x, y, z, r;
            cin >> x >> y >> z >> r;
            m[i] = {x, y, z};
            dist[i] = r;
        }
        vector<pair<ld, pair<ll, ll>>> p;
        rep(i, N - 1){
            for(int j = i + 1; j < N; j++){
                auto [xi, yi, zi] = m[i];
                auto [xj, yj, zj] = m[j];
                ld dx = xi - xj, dy = yi - yj, dz = zi - zj;
                ld d = max(sqrt((dx * dx + dy * dy + dz * dz)) - (dist[i] + dist[j]), (ld)0);
                p.push_back({d, {i, j}});
            }
        }
        sort(nall(p));
        UnionFind uf(N);
        ld preans = 0;
        rep(i, (int)p.size()){
            ll a = p[i].second.first, b = p[i].second.second;
            if(uf.Same(a, b) == false){
                uf.Unite(a, b);
                preans += p[i].first;
            }
        }
        ans.push_back(preans);
    }
    rep(i, (int)ans.size()){
        cout << fixed << setprecision(3) << ans[i] << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3624
final_rank: 3

code_snippet: #include <iostream>
#include <vector>
#include <iomanip>
#include <algorithm>
#include <tuple>
#include <set>
#include <map>
#include <bitset>
#include <cmath>
#include <deque>
#include <queue>
#include <stack>
#include <cassert>
#include <unordered_set>
#include <unordered_map>
#include <cmath>
using namespace std;
typedef long long ll;
#define rep(i, n) for (ll i = 0; i < (ll)(n); i++)
#define all(v) v.begin(), v.end()

ll llpow(ll a, ll t)
{
  ll res = 1;
  rep(i, t) res *= a;
  return res;
}

ll inf = std::numeric_limits<ll>::max();

ll findp(vector<ll> &ps, ll u)
{
  if (ps[u] != u)
  {
    ps[u] = findp(ps, ps[u]);
  }
  return ps[u];
}

int main()
{
  vector<double> anss;
  while (true)
  {
    ll n;
    cin >> n;
    if (!n)
    {
      break;
    }
    vector<vector<double>> vec(n);
    rep(i, n)
    {
      double x, y, z, r;
      cin >> x >> y >> z >> r;
      vec[i] = {x, y, z, r};
    }
    vector<tuple<double, ll, ll>> g;
    rep(i, n)
    {
      rep(j, n)
      {
        if (i == j)
        {
          continue;
        }
        double d = pow(pow(vec[i][0] - vec[j][0], 2) + pow(vec[i][1] - vec[j][1], 2) + pow(vec[i][2] - vec[j][2], 2), 0.5);
        d = max(d - vec[i][3] - vec[j][3], (double)0);
        g.push_back(make_tuple(d, i, j));
      }
    }
    sort(all(g));
    vector<ll> ps(n);
    rep(i, n)
    {
      ps[i] = i;
    }
    double ans = 0;
    rep(i, g.size())
    {
      double d;
      ll s, t;
      tie(d, s, t) = g[i];
      ll sp = findp(ps, s);
      ll tp = findp(ps, t);
      if (sp != tp)
      {
        ps[tp] = sp;
        ans += d;
      }
    }
    anss.push_back(ans);
  }
  cout << fixed << setprecision(3);
  for (auto ans : anss)
  {
    cout << ans << endl;
  }
}
accuracy: 1
time_ms: 20
memory_kb: 4084
final_rank: 18

code_snippet: #include <iostream>
#include <vector>
#include <string>
#include <cmath>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <functional>
#include <stack>
#include <numeric>

using namespace std;
using l = long long;
using ul = unsigned long long;

const int inf =  2147483647;         // 2e9     1 << 30
const l INF = 9223372036854775807;  // 9e18    1LL << 60

#define r(i, n) for (l i = 0; i < n; ++i)
#define r1(i, n) for (l i = 1; i < n; ++i)
#define r0(i) for (l i = -1; i < 2; ++i)
#define pll pair<l, l>

void YesNo(bool s=false) {
    if (s) cout<<"Yes"<<endl;
    else cout<<"No"<<endl;
}

struct UnionFind {
    vector<l> parent, rank, size;
    l tree_count;

    UnionFind(l n) : parent(n), rank(n, 0), size(n, 1), tree_count(n) {
        for (l i = 0; i < n; i++) parent[i] = i;
    }
    
    l find(l x) {
        if (parent[x] == x) return x;
        return parent[x] = find(parent[x]);  // パス圧縮
    }
    bool unite(pll xy) {
        l rx = find(xy.first);
        l ry = find(xy.second);
        if (rx == ry) return false;
        if (rank[rx] < rank[ry]) swap(rx, ry);
        parent[ry] = rx;
        size[rx] += size[ry];
        if (rank[rx] == rank[ry]) rank[rx]++;

        tree_count--;

        return true;
    }
    
    bool same(pll xy) {
        return find(xy.first) == find(xy.second);
    }
    
    l getSize(l x) {
        return size[find(x)];
    }
};

void demo() {
    l n;cin >> n;
    if (n == 0) exit(0);
    
    vector<vector<double>> cells;

    r(i, n) {
        double x, y, z, r;cin >> x >> y >> z >> r;
        cells.push_back({x, y, z, r});
    }

    vector<vector<double>> roads;

    r(i, n) r(j, i) {
        double d = sqrt(pow(cells[i][0]-cells[j][0], 2) + pow(cells[i][1]-cells[j][1], 2) + pow(cells[i][2]-cells[j][2], 2));

        double cost = max(0., d - cells[i][3] - cells[j][3]);
        roads.push_back({cost, double(i), double(j)});
    }

    sort(roads.begin(), roads.end());

    UnionFind uf(n);

    double ans = 0;



    for (auto road : roads) {
        if (uf.unite({road[1], road[2]})) ans += road[0];
    }

    printf("%.3f\n", ans);
}

int main() {
    while(true) demo();
}
accuracy: 1
time_ms: 10
memory_kb: 3880
final_rank: 11

code_snippet: // author: Yuichiro Kurose

#include <bits/stdc++.h>
using namespace std;

class UnionFind {
public:
  vector<int> par;
  vector<int> siz;
  UnionFind(int n) {
    par = vector<int>(n, -1);
    siz = vector<int>(n, 1);
  }
  int root(int x) {
    if (par[x] < 0) {
      return x;
    }
    return par[x] = root(par[x]);
  }
  void unite(int u, int v) {
    int root_u = root(u);
    int root_v = root(v);
    if (root_u == root_v) {
      return;
    }
    if (siz[root_u] < siz[root_v]) {
      par[root_u] = root_v;
      siz[root_v] += siz[root_u];
    } else {
      par[root_v] = root_u;
      siz[root_u] += siz[root_v];
    }
  }
  bool same(int u, int v) {
    if (root(u) == root(v)) {
      return true;
    }
    return false;
  }
};

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  while (true) {
    int n;
    cin >> n;
    if (n == 0) {
      break;
    }
    vector<double> x(n), y(n), z(n), r(n);
    for (int i = 0; i < n; i++) {
      cin >> x[i] >> y[i] >> z[i] >> r[i];
    }
    vector<tuple<double, int, int>> edges;
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < n; j++) {
        double dist = sqrt(pow(x[i] - x[j], 2) + pow(y[i] - y[j], 2) + pow(z[i] - z[j], 2));
        double l = r[i] + r[j];
        if (dist < l) {
          edges.push_back(make_tuple(0, i, j));
        } else {
          edges.push_back(make_tuple(dist - l, i, j));
        }
      }
    }
    sort(edges.begin(), edges.end());
    UnionFind uf(n);
    double ans = 0;
    for (auto tup : edges) {
      double w = get<0>(tup);
      int u = get<1>(tup), v = get<2>(tup);
      if (!uf.same(u, v)) {
        ans += w;
        uf.unite(u, v);
      }
    }
    cout << fixed << setprecision(3) << ans << endl;
  }
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3804
final_rank: 10

code_snippet: #include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); i++)
typedef unsigned long long int ull;
typedef long long ll;
using namespace std;
const int INTINF = 1001001001;
const long long LLINF = 1e18;
const int MOD = 998244353;
#define Pii pair<int, int>
#define Pli pair<long long, int>
#define Pil pair<int, long long>
#define Pid pair<int, double>
#define Pdi pair<double, int>
#define Psi pair<string, int>
#define Tiii tuple<int, int, int>
#define Tlii tuple<long long, int, int>
#define chmax(x, y) x = max(x, y)
#define pqueue priority_queue
#define pb push_back

int dy[] = {-1, 0, 1, 0};
int dx[] = {0, 1, 0, -1};
int ddy[] = {-1, -1, -1, 0, 0, 0, 1, 1, 1};
int ddx[] = {-1, 0, 1, -1, 0, 1, -1, 0, 1};

struct Cell { double x, y, z, r; };

double calcDist(struct Cell &a, struct Cell &b)
{
	auto [x1, y1, z1, r1] = a;
	auto [x2, y2, z2, r2] = b;
	double x = x1 - x2, y = y1 - y2, z = z1 - z2;
	double r = r1 + r2;
	double dist = sqrt(x*x+y*y+z*z);
	return max(0., dist - r);
}

void solve()
{
	int N;
	while (cin >> N, N)
	{
		vector<Cell> cells(N);
		rep (i, N)
		{
			double x, y, z, r;
			cin >> x >> y >> z >> r;
			cells[i] = {x, y, z, r};
		}

		vector<vector<Pid>> E(N, vector<Pid> (N));
		rep (i, N) rep (j, N) E[i].pb({j, calcDist(cells[i], cells[j])});
		double ans = 0;
		pqueue<Pdi, vector<Pdi>, greater<Pdi>> queue;
		vector<bool> visited(N);
		for (auto [next, dist] : E[0]) queue.push({dist, next});
		visited[0] = true;
		while (!queue.empty())
		{
			auto [cost, current] = queue.top();
			queue.pop();
			if (visited[current]) continue;
			visited[current] = true;
			ans += cost;
			for (auto [next, dist] : E[current]) queue.push({dist, next});
		}
		printf("%.3f\n", ans);
	}
}

#ifdef DEBUG
int Qnum = 3;
#else
int Qnum = 1;
#endif

int main()
{
	while (Qnum--)
	{
		solve();
	}
}
accuracy: 1
time_ms: 20
memory_kb: 3976
final_rank: 15

code_snippet: // 1127
#include <iostream>
#include <vector>
#include <queue>
#include <cmath>
#include <cstdio>

using namespace std;

struct cell
{
	double x, y, z, r;
};

double d(double x) { return x * x; }

double calcDist(cell& a, cell& b)
{
	double dist = sqrt(d(a.x - b.x) + d(a.y - b.y) + d(a.z - b.z));
	dist -= (a.r + b.r);
	return max(0., dist);
}

int main()
{
	while (1)
	{
		int N;
		cin >> N;
		if (N == 0) break;
		vector<cell> cells(N);
		for (int i = 0; i < N; i++) cin >> cells[i].x >> cells[i].y >> cells[i].z >> cells[i].r;
		vector<vector<double>> E(N, vector<double>(N));
		for (int i = 0; i < N; i++) for (int j = i + 1; j < N; j++) E[i][j] = E[j][i] = calcDist(cells[i], cells[j]);
		double ans = 0;
		vector<bool> united(N);
		priority_queue<pair<double, int>, vector<pair<double, int>> ,greater<pair<double, int>>> queue;
		for (int i = 0; i < N; i++) queue.push({E[0][i], i});
		united[0] = true;
		while (!queue.empty())
		{
			auto [c, current] = queue.top();
			queue.pop();
			if (united[current]) continue;
			united[current] = true;
			ans += c;
			for (int i = 0; i < N; i++) queue.push({ E[current][i], i });
		}
		printf("%.3f\n", ans);
	}
}
accuracy: 1
time_ms: 10
memory_kb: 3748
final_rank: 9

code_snippet: #include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); i++)
typedef unsigned long long int ull;
typedef long long ll;
using namespace std;
const int INF = 1001001001;
const int MOD = 998244353;
#define Pint pair<int, int>
#define Pli pair<long long, int>
#define Pid pair<int, double>
#define Pdi pair<double, int>
#define Tint tuple<int, int, int>
#define chmax(x, y) x = max(x, y)

struct cell
{
	double x, y, z, r;
};

double calcDist(cell &a, cell &b)
{
	auto [x1, y1, z1, r1] = a;
	auto [x2, y2, z2, r2] = b;
	double dist = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2));
	double ret = dist - (r1 + r2);
	return max(0.0, ret);
}

void solve(void)
{
	while (1)
	{
		int N;
		cin >> N;
		if (N == 0) break;
		vector<cell> cells(N);
		rep (i, N)
		{
			double x, y, z, r;
			cin >> x >> y >> z >> r;
			cells[i] = {x, y, z, r};
		}
		vector<vector<Pid>> E(N);
		for (int i = 0; i < N; i++)
		{
			for (int j = 0; j < N; j++)
			{
				E[i].push_back({j, calcDist(cells[i], cells[j])});
			}
		}
		priority_queue<Pdi, vector<Pdi>, greater<Pdi>> queue;
		vector<bool> visited(N);
		visited[0] = true;
		for (auto[next, dist] : E[0]) queue.push({dist, next});
		double ans = 0;
		while (!queue.empty())
		{
			auto [c, current] = queue.top();
			queue.pop();
			if (visited[current]) continue;
			visited[current] = true;
			ans += c;
			for (auto [next, dist] : E[current]) queue.push({dist, next});
		}
		printf("%.3f\n", ans);
	}
}

#ifdef DEBUG
int Qnum = 3;
#else
int Qnum = 1;
#endif

int main()
{
	while (Qnum--)
	{
		solve();
	}
}
accuracy: 1
time_ms: 10
memory_kb: 3952
final_rank: 13

code_snippet: #include <bits/stdc++.h>
#define rep(i, a, b) for (ll i = a; i < b; i++)
#define rrep(i, a, b) for (ll i = a; i >= b; i--)
#define fore(i, a) for (auto &i : a)
#define all(x) (x).begin(), (x).end()
#define YES cout << "Yes" << endl
#define NO cout << "No" << endl
#define YN                                                                     \
  {                                                                            \
    cout << "Yes" << endl;                                                     \
  }                                                                            \
  else {                                                                       \
    cout << "No" << endl;                                                      \
  } // if(a==b)YN;
#define FAIL cout << -1 << endl
#pragma GCC optimize("-O3")

using namespace std;
using ll = long long;
using ld = long double;
using i128 = __int128_t;
using pll = pair<ll, ll>;
using pld = pair<ld, ld>;
using matrix = vector<vector<ll>>;
using matrixld = vector<vector<ld>>;
using matrixb = vector<vector<bool>>;
using onevec = vector<ll>;
using onevecld = vector<ld>;
using onevecb = vector<bool>;
using lset = set<ll>;

const ll INFL = 1LL << 60;
template <class T> T chmin(T &a, T b) {
  if (a > b) {
    a = b;
  }
  return a;
}
template <class T> T chmax(T &a, T b) {
  if (a < b) {
    a = b;
  }
  return a;
}
template <typename T> ll lsize(const T &container) {
  return static_cast<ll>(container.size());
}
template <typename T> bool ifbit(T number, ll bit) {
  return (number & (1LL << bit)) != 0;
}
template <typename T> T twice(const T &a) { return a * a; }
template <typename T> T bits_count(T v) { return __builtin_popcountll(v); }

template <typename T> T factorial(T n) {
  T result = 1;
  for (T i = 1; i <= n; ++i) {
    result *= i;
  }
  return result;
}

template <typename T> T pdistance(const vector<pair<T, T>> &xy, int i, int j) {
  return sqrt(twice(xy[i].first - xy[j].first) +
              twice(xy[i].second - xy[j].second));
}
template <typename T>
int isperp(const vector<pair<T, T>> &xyz, int i, int j, int k) {
  T dx1 = xyz[i].first - xyz[j].first, dy1 = xyz[i].second - xyz[j].second;
  T dx2 = xyz[k].first - xyz[j].first, dy2 = xyz[k].second - xyz[j].second;

  T dot = dx1 * dx2 + dy1 * dy2;

  return (dot > 0) ? 0 : (dot == 0) ? 1 : -1;
}

template <typename T>
T crossp(const vector<pair<T, T>> &xyz, int i, int j, int k) {
  T dx1 = xyz[i].first - xyz[j].first, dy1 = xyz[i].second - xyz[j].second;
  T dx2 = xyz[k].first - xyz[j].first, dy2 = xyz[k].second - xyz[j].second;

  return dx1 * dy2 - dy1 * dx2;
}

template <typename T> T mod_exp(T base, T exp, T mod) {
  T result = 1;
  while (exp > 0) {
    if (exp & 1)
      result = (result * base) % mod;
    base = (base * base) % mod;
    exp >>= 1;
  }
  return result;
}

template <typename T> void print(T value, int precision) {
  cout << fixed << setprecision(precision) << value << endl;
}

template <typename... Args> void in(Args &...args) { (cin >> ... >> args); }

template <typename... Args> void out(const Args &...args) {
  constexpr size_t n = sizeof...(args);
  size_t i = 0;
  ((cout << args << (++i < n ? " " : "")), ...) << "\n";
}

const int dx[8] = {1, 0, -1, 0, 1, 1, -1, -1};
const int dy[8] = {0, 1, 0, -1, 1, -1, 1, -1};
string strrep(const string &s, const string &from, const string &to) {

  unordered_map<char, char> trans;
  for (size_t i = 0; i < from.size(); ++i) {
    trans[from[i]] = to[i];
  }

  string res = s;
  for (char &c : res) {
    if (trans.count(c)) {
      c = trans[c];
    }
  }
  return res;
}
template <typename T> bool isprime(T N) {
  if (N < 2)
    return false;
  for (T i = 2; i * i <= N; i++) {
    if (N % i == 0)
      return false;
  }
  return true;
}
template <typename T>
using min_priority_queue = priority_queue<T, vector<T>, greater<T>>;
vector<pair<char, int>> rle(const string &s) {
  vector<pair<char, int>> res;
  for (int i = 0, cnt; i < s.size(); i += cnt) {
    cnt = 1;
    while (i + cnt < s.size() && s[i] == s[i + cnt])
      cnt++;
    res.emplace_back(s[i], cnt);
  }
  return res;
}
/*--------------------------------------------------------
                         \0w0/
                        OwOkaomoji
                     ｡˚ (¦3ꇤ )3 ⋆｡˚✩
----------------------------------------------------------*/
/* UnionFind：素集合系管理の構造体(union by rank)
    isSame(x, y): x と y が同じ集合にいるか。 計算量はならし O(α(n))
    unite(x, y): x と y を同じ集合にする。計算量はならし O(α(n))
*/
struct UnionFind { // The range of node number is 0 to n-1
  vector<ll> rank, parents;
  UnionFind() {}
  UnionFind(ll n) { // make n trees.
    rank.resize(n, 0);
    parents.resize(n, 0);
    rep(i, 0, n) { makeTree(i); }
  }
  void makeTree(ll x) {
    parents[x] = x; // the parent of x is x
    rank[x] = 0;
  }
  bool isSame(ll x, ll y) { return findRoot(x) == findRoot(y); }
  void unite(ll x, ll y) {
    x = findRoot(x);
    y = findRoot(y);
    if (rank[x] > rank[y]) {
      parents[y] = x;
    } else {
      parents[x] = y;
      if (rank[x] == rank[y]) {
        rank[y]++;
      }
    }
  }
  int findRoot(ll x) {
    if (x != parents[x])
      parents[x] = findRoot(parents[x]);
    return parents[x];
  }
};

// 辺の定義
struct Edge {
  long long u;
  long long v;
  ld cost;
};
bool comp_e(const Edge &e1, const Edge &e2) {
  return e1.cost < e2.cost;
} // 辺を直接比較するための関数

/* Kruskal :クラスカル法で minimum spanning tree を求める構造体
    入力: 辺のvector, 頂点数V
    最小全域木の重みの総和: sum
    計算量: O(|E|log|V|)
*/
struct Kruskal {
  UnionFind uft;
  ld sum;  // 最小全域木の重みの総和
  ll size; // 木の数
  vector<Edge> edges;
  ll V;
  ll K;
  Kruskal(const vector<Edge> &edges_, ll V_, ll K_)
      : edges(edges_), V(V_), K(K_), size(V_) {
    init();
  }
  void init() {
    sort(edges.begin(), edges.end(), comp_e); // 辺の重みでソート
    uft = UnionFind(V);
    sum = 0;
    for (auto e : edges) {
      if (size == K) {
        break;
      }
      if (!uft.isSame(e.u, e.v)) { // 閉路にならなければ加える
        uft.unite(e.u, e.v);
        sum += e.cost;
        size--;
      }
    }
  }
};
bool is_connected(vector<ld> sph1, vector<ld> sph2) {
  ld x1 = sph1[0], y1 = sph1[1], z1 = sph1[2], r1 = sph1[3];
  ld x2 = sph2[0], y2 = sph2[1], z2 = sph2[2], r2 = sph2[3];
  return twice(r1 + r2) >= twice(x1 - x2) + twice(y1 - y2) + twice(z1 - z2);
}
// グラフが隣接リストで与えられる時はクラスカル法
int main() {

  ll N; // 頂点の数、辺の数,木の数
  in(N);
  while (N != 0) {
    vector<vector<ld>> sphere(N);
    rep(i, 0, N) {
      vector<ld> sph(4);
      fore(x, sph) { in(x); }
      sphere[i] = sph;
    }
    vector<Edge> edges(N * N);
    rep(i, 0, N) rep(j, i + 1, N) {
      if (is_connected(sphere[i], sphere[j])) {
        edges[i * N + j] = {i, j, 0.0};
      } else {
        ld d = sqrt(twice(sphere[i][0] - sphere[j][0]) +
                    twice(sphere[i][1] - sphere[j][1]) +
                    twice(sphere[i][2] - sphere[j][2]));
        edges[i * N + j] = {i, j, d - sphere[i][3] - sphere[j][3]};
      }
    }
    // rep(i, 0, M) {
    //   ll s, t, w; // start, goal, weight
    //   in(s, t, w);
    //   s--;
    //   t--;
    //   Edge e = {s, t, w};
    //   edges[i] = e;
    // }
    Kruskal krs(edges, N, 1);
    print(krs.sum,3);
    in(N);
  }
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 4184
final_rank: 16

code_snippet: //#include <bits/stdc++.h>
#include <iostream>
#include <string>
#include <cstdio>
#include <vector>
#include <cmath>
#include <algorithm>
#include <functional>
#include <iomanip>
#include <queue>
#include <random>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <stack>
#include <utility>
#include <cassert>
#include <complex>
#include <numeric>
#include <array>
#include <chrono>
#include <tuple>
#include <deque>
using namespace std;
//#include <atcoder/all>
//using namespace atcoder;

using ll = long long;
using P = pair<int, int>;
using PLL = pair<ll, ll>;

const int INF = 0x3fffffff;
const ll LINF = 0x1fffffffffffffff;

#define rep(i,n) for (int i = 0; i < (n); i++)
#define rrep(i,n) for (int i = (n) - 1; i >= 0; i--)
#define all(c) (c).begin(), (c).end()
#define rall(c) (c).rbegin(), (c).rend()
template<typename T, typename U> inline bool chmax(T &a, const U &b) { bool compare = a < b; if (compare) a = b; return compare;}
template<typename T, typename U> inline bool chmin(T &a, const U &b) { bool compare = a > b; if (compare) a = b; return compare;}
template<typename T, typename U> std::ostream &operator<< (std::ostream &os, std::pair<T, U> p){ os << p.first << ' ' << p.second; return os; }

vector<int> di = {-1, 1, 0, 0, -1, 1, 1, -1};
vector<int> dj = {0, 0, -1, 1, -1, -1, 1, 1};

ll intPow(ll a, ll b){ ll ans = 1; while(b){ if(b & 1) ans *= a; a *= a; b /= 2; } return ans; }
ll modPow(ll a, ll b, ll p){ ll ans = 1; while(b){ if(b & 1) (ans *= a) %= p; (a *= a) %= p; b /= 2; } return ans; }

struct UnionFind {
    vector<int> data;

    UnionFind(int n = 1) {
        data.assign(n, -1);
    }

    int leader(int x) {
        if (data[x] < 0) return x;
        else {
            int r = leader(data[x]);
            return data[x] = r;
        }
    }

    bool same(int x, int y) {
        return leader(x) == leader(y);
    }

    int size(int x) {
        return -data[leader(x)];
    }

    bool merge(int x, int y) {
        x = leader(x);
        y = leader(y);
        if (x == y) return false;
        if (data[x] > data[y]) swap(x, y);
        data[x] += data[y];
        data[y] = x;
        return true;
    }
    
};
using ld = long double;

int main()
{
    cout << fixed << setprecision(3);
    rep(qi, 100000000) {
        int n;
        cin >> n;
        if (n == 0) {
            return 0;
        }

        vector<ld> x(n), y(n), z(n), r(n);
        rep(i, n) cin >> x[i] >> y[i] >> z[i] >> r[i];
        UnionFind uf(n);
        vector<pair<ld, P>> path;
        for (int i = 0; i < n; i++) {
            for (int j = 1; j < n; j++) {
                ld xx = x[i] - x[j], yy = y[i] - y[j], zz = z[i] - z[j];
                ld d = sqrt(xx * xx + yy * yy + zz * zz) - r[i] - r[j];
                if (d <= 0) uf.merge(i, j);
                path.emplace_back(d, P{i, j});
            }
        }
        ld ans = 0;
        sort(all(path));
        for (auto [d, p] : path) {
            auto [i, j] = p;
            if (uf.same(i, j)) continue;
            ans += d;
            uf.merge(i, j);
        } 
        cout << ans << endl;
    }

    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 4060
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for(int i=0;i<(n);i++)
#define all(a) a.begin(), a.end()
#define rall(a) a.rbegin(), a.rend()
using ll = long long;
using pi = pair<double, int>; 
const int di[]={1,-1,0,0};
const int dj[]={0,0,1,-1};
const int INF=1e9;
struct Edge {
    double wei;
    int v;
};
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    while(cin >> n && n!=0) {
        vector<double> x(n), y(n), z(n), r(n);
        rep(i, n) cin >> x[i] >> y[i] >> z[i] >> r[i];
        vector<vector<Edge>> G(n);
        rep(i, n) rep(j, n) {
            double tmp;
            tmp=sqrt(pow(x[i]-x[j], 2)+pow(y[i]-y[j], 2)+pow(z[i]-z[j], 2));
            if(tmp<=r[i]+r[j]) tmp=0;
            else tmp-=r[i]+r[j];
            G[i].push_back({tmp, j});
            G[j].push_back({tmp, i});        
        }
        vector<int> used(n, false);
        priority_queue<pi, vector<pi>, greater<pi>> pq;
        used[0]=true;
        for(auto u:G[0]) pq.push({u.wei, u.v});
        double ans=0.0;
        while(!pq.empty()) {
            auto [w, u]=pq.top();
            pq.pop();
            if(used[u]) continue;
            used[u]=true;
            ans+=w;
            for(auto nu:G[u]) {
                if(used[nu.v]) continue;
                pq.push({nu.wei, nu.v});
            }
        }
        cout << fixed << setprecision(3) << ans << endl;
    }

    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 4224
final_rank: 17

code_snippet: // 1127
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <queue>

struct cell
{
	double x, y, z, r;
};

double calcDist(struct cell& cella, struct cell& cellb)
{
	double dx = cella.x - cellb.x;
	double dy = cella.y - cellb.y;
	double dz = cella.z - cellb.z;
	double dr = cella.r + cellb.r;
	double ddd = std::sqrt(dx * dx + dy * dy + dz * dz);
	if (dr > ddd)
	{
		if (ddd + std::min(cella.r, cellb.r) <= std::max(cella.r, cellb.r))	return -100;
		else return 0;
	}
	else return ddd - dr;
}

void solve(int N)
{
	std::vector<cell> cells(N);
	std::vector<bool> involved(N);
	for (int i = 0; i < N; i++) std::cin >> cells[i].x >> cells[i].y >> cells[i].z >> cells[i].r;

	for (int i = 0; i < N; i++)
	{
		for (int j = i + 1; j < N; j++)
		{
			if (involved[i] || involved[j]) continue;
			double dist = calcDist(cells[i], cells[j]);
			if (dist < 0)
			{
				if (cells[i].r > cells[j].r) involved[j] = true;
				else involved[i] = true;
			}
		}
	}

	std::vector<std::vector<std::pair<int, double>>> E(N);
	for (int i = 0; i < N; i++)
	{
		if (involved[i]) continue;
		for (int j = i + 1; j < N; j++)
		{
			if (involved[j]) continue;
			double dist = calcDist(cells[i], cells[j]);
			E[i].push_back({ j, dist });
			E[j].push_back({ i, dist });
		}
	}


	std::vector<bool> visited(N);
	std::priority_queue<
		std::pair<double, int>,
		std::vector<std::pair<double, int>>,
		std::greater<std::pair<double, int>>
	> queue;

	for (int i = 0; i < N; i++)
	{
		if (involved[i]) continue;
		if (E[i].size() == 0) continue;
		visited[i] = true;
		for (auto [next, dist] : E[i])
		{
			queue.push({ dist, next });
		}
		break;
	}

	double ans = 0;
	while (!queue.empty())
	{
		auto [dist, current] = queue.top();
		queue.pop();
		if (visited[current]) continue;
		visited[current] = true;
		ans += dist;
		for (auto [next, cost] : E[current]) queue.push({ cost, next });
	}

	printf("%.3f\n", ans);
}

int main()
{
	while (1)
	{
		int N;
		std::cin >> N;
		if (N == 0) break;
		solve(N);
	}
}
accuracy: 1
time_ms: 10
memory_kb: 3892
final_rank: 12

code_snippet: #include<iostream>
#include<vector>
#include<cmath>
#include<iomanip>
#include<algorithm>
using namespace std;

struct UnionFind{
	vector<int> parent,size;
	UnionFind(int n): parent(n,-1), size(n,1){}
	int root(int x){
		if(parent[x] == -1) return x;
		else return root(parent[x]);
	}
	bool same(int x, int y){
		return root(x)==root(y);
	}
	void unite(int x, int y){
		if(!same(x,y)){
			int rx = root(x), ry = root(y);
			if(size[rx] > size[ry]){
				parent[ry] = rx;
				size[rx] += size[ry];
			}else{
				parent[rx] = ry;
				size[ry] += size[rx];
			}
		}
	}
};

struct Edge{
	int s,t;
	double d;
};

bool comp_e(Edge &a, Edge &b){
	return a.d < b.d;
}

void solve(int n){
	vector<double> x(n),y(n),z(n),r(n);
	for(int i = 0; i < n; i++){
		cin >> x[i] >> y[i] >> z[i] >> r[i];
	}
	vector<Edge> list(0);
	for(int i = 0; i < n; i++){
		for(int j = i+1; j < n; j++){
			double dist = hypot(hypot(x[i]-x[j], y[i]-y[j]), z[i]-z[j])-r[i]-r[j];
			dist = dist < 0 ? 0: dist;
			Edge edge = {i,j,dist};
			list.push_back(edge);
		}
	}
	UnionFind uf(n);
	double ans = 0;
	sort(list.begin(), list.end(), comp_e);
	for(int i = 0; i < n*(n-1)/2; i++){
		if(!uf.same(list[i].s, list[i].t)){
			ans += list[i].d;
			uf.unite(list[i].s, list[i].t);
		}
	}
	cout << fixed << setprecision(3) << ans << endl;
}

int main(){
	int n;
	cin >> n;
	while(n!=0){
		solve(n);
		cin >> n;
	}
}
accuracy: 1
time_ms: 10
memory_kb: 3476
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < (int)(n); i++) //forループ
#define reps(i, m, n) for (int i = (int)(m); i < (int)(n); i++) //forループ(開始位置指定)
#define rrep(i, n) for (int i = n-1; i >= 0; i--) //forループ逆順
#define all(a) (a).begin(), (a).end() //all
#define rall(a) (a).rbegin(), (a).rend() //逆all

#define ll long long //long long型

#define alphabet "abcdefghijklmnopqrstuvwxyz" //英小文字列
#define alphabet_A "ABCDEFGHIJKLMNOPQRSTUVWXYZ" //英大文字列
#define pi acos(-1) //円周率

#define move_X4 vector<int> {1, 0, -1, 0} //4方向への移動
#define move_Y4 vector<int> {0, 1, 0, -1} //4方向への移動

#define move_X8 vector<int> {1, 1, 0, -1, -1, -1, 0, 1} //8方向への移動
#define move_Y8 vector<int> {0, 1, 1, 1, 0, -1, -1, -1} //8方向への移動

vector<int> node;

int root(int a)
{
    int tmpRoot;
    while (true)
    {
        if (node[a] == -1)
        {
            tmpRoot = a;
            break;
        }

        a = node[a];
    }

    while (true)
    {
        int tmp = node[a];

        if (tmp == -1)
        {
            break;
        }

        node[a] = tmpRoot;
        a = tmp;
    }

    return tmpRoot;
}

int main()
{
    while (true)
    {
        int n;
        cin>>n;

        if (n == 0)
        {
            break;
        }

        vector<tuple<double, double, double, double>> a(n);
        rep(i, n)
        {
            double x, y, z, r;
            cin>>x>>y>>z>>r;
            a[i] = make_tuple(x, y, z, r);
        }

        vector<tuple<double, int, int>> edge;
        rep(i, n)
        {
            reps(j, i+1, n)
            {
                double x1, y1, z1, r1, x2, y2, z2, r2;
                x1 = get<0>(a[i]), y1 = get<1>(a[i]), z1 = get<2>(a[i]), r1 = get<3>(a[i]);
                x2 = get<0>(a[j]), y2 = get<1>(a[j]), z2 = get<2>(a[j]), r2 = get<3>(a[j]);
                double dist = max(sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2) + pow(z1 - z2, 2)) - r1 - r2, (double)0);
                edge.push_back(make_tuple(dist, i, j));
            }
        }

        sort(all(edge));
        node = vector<int>(n, -1);
        double answer = 0;
        rep(i, edge.size())
        {
            double dist = get<0>(edge[i]);
            int u = get<1>(edge[i]), v = get<2>(edge[i]);

            if (root(u) != root(v))
            {
                answer += dist;
                node[root(u)] = root(v);
            }
        }

        cout<<fixed<<setprecision(3);
        cout<<answer<<endl;
    }
}
accuracy: 1
time_ms: 10
memory_kb: 3552
final_rank: 2

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<ll,ll> pi;
#define FOR(i,l,r) for(ll i=l;i<r;i++)
#define REP(i,n) FOR(i,0,n)
#define ALL(A) A.begin(),A.end()
int main(){
    while(1){
        ll N;cin>>N;
        if(!N)return 0;
        vector<ld>X(N),Y(N),Z(N),R(N);
        REP(i,N)cin>>X[i]>>Y[i]>>Z[i]>>R[i];
        vector<pair<ld,pi>>es;
        REP(i,N)REP(j,i){
            ld d=sqrtl((X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j])+(Z[i]-Z[j])*(Z[i]-Z[j]));
            es.emplace_back(make_pair(max((ld)0,d-R[i]-R[j]),pi(j,i)));
        }
        sort(ALL(es));
        ld ans=0;
        vector<ll>nec(N,-1);
        auto leader=[&](ll v){
            while(nec[v]>=0)v=nec[v];
            return v;
        };
        for(auto[c,p]:es)if(leader(p.first)!=leader(p.second)){
            ll u=leader(p.first),v=leader(p.second);
            if(nec[u]<nec[v])swap(u,v);
            nec[v]+=nec[u];
            nec[u]=v;
            ans+=c;
        }
        printf("%.3Lf\n",ans);
    }
}
accuracy: 1
time_ms: 10
memory_kb: 3712
final_rank: 6

code_snippet: #include <bits/stdc++.h>

using namespace std;
using ll = long long;
ll MOD = 100'000'000;
ll inf = (1LL << 62);

// clang-format off
auto getll(){ll n; cin >> n; return n;}
auto getstr(){string s; cin >> s; return s;}
auto getdb(){double n; cin >> n; return n;}
auto getvll(ll n){vector<ll> a(n); for (ll i = 0; i < n; ++i) a[i] = getll(); return a;}
auto getvstr(ll n){vector<string> a(n); for (ll i = 0; i < n; ++i) a[i] = getstr(); return a;}
auto getvdb(ll n){vector<double> a(n); for (ll i = 0; i < n; ++i) a[i] = getdb(); return a;}
// clang-format on

class UnionFind {
  private:
    std::vector<int> parent;

  public:
    UnionFind() = default;
    explicit UnionFind(size_t n) : parent(n, -1) {}
    int find(int i) {
        if (parent[i] < 0) {
            return i;
        }
        return (parent[i] = find(parent[i]));
    }
    void merge(int a, int b) {
        a = find(a);
        b = find(b);
        if (a != b) {
            if (-parent[a] < -parent[b]) {
                swap(a, b);
            }
            parent[a] += parent[b];
            parent[b] = a;
        }
    }
    bool same(int a, int b) { return find(a) == find(b); }
    int size(int i) { return -parent[find(i)]; }
};

struct Edge {
    ll from;
    ll to;
    double cost;
};

int main() {
    vector<double> tmp;
    while (true) {
        ll n;
        cin >> n;
        if (n == 0)
            break;
        vector<double> x(n), y(n), z(n), r(n);
        for (ll i = 0; i < n; ++i) {
            cin >> x[i] >> y[i] >> z[i] >> r[i];
        }
        UnionFind uf(n);
        vector<Edge> edges;
        for (ll i = 0; i < n; ++i) {
            for (ll j = 0; j < n; ++j) {
                auto dx = x[i] - x[j], dy = y[i] - y[j], dz = z[i] - z[j];
                auto sq = dx * dx + dy * dy + dz * dz;
                auto dist = sqrt(sq) > r[i] + r[j] ? sqrt(sq) - r[i] - r[j] : 0;
                edges.push_back({i, j, dist});
            }
        }
        sort(edges.begin(), edges.end(),
             [](auto& a, auto& b) { return a.cost < b.cost; });
        double ans = 0;
        ll cnt = 0;
        for (auto& e : edges) {
            if (!uf.same(e.from, e.to)) {
                uf.merge(e.from, e.to);
                ans += e.cost;
                if (cnt == n - 1)
                    break;
            }
        }
        tmp.push_back(ans);
    }
    cout << fixed << setprecision(3);
    for (auto& x : tmp) {
        cout << x << endl;
    }
}
accuracy: 1
time_ms: 10
memory_kb: 3632
final_rank: 4

code_snippet: #include <bits/stdc++.h>
//#include <atcoder/all>
#include <unordered_set>
#include <functional>
using namespace std;
//using namespace atcoder;
using ll = long long;
using P = pair<int, int>;
#define rep(i, n) for (int i = 0; i < (n); i++)
//void chmin(ll & a, ll b) { a = min(a, b); }
//using mint = modint1000000007;

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

double square(double a, double b) {
	return (a - b) * (a - b);
}

double calc(point p1, point p2) {
	double x = square(p1.x, p2.x);
	double y = square(p1.y, p2.y);
	double z = square(p1.z,p2.z);
	return sqrt(x + y + z);
}

class UnionFind {
public:
	int par[109];
	int siz[109];

	void init(int n) {
		rep(i, n) par[i] = -1;
		rep(i, n) siz[i] = 1;
	}

	int root(int v) {
		if (par[v] == -1) {
			return v;
		}
		return root(par[v]);
	}

	void unite(int u, int v) {
		int ru = root(u);
		int rv = root(v);
		if (ru == rv) return;
		if (siz[ru] > siz[rv]) {
			siz[ru] = siz[rv] + siz[ru];
			par[rv] = ru;
		}
		else {
			siz[rv] = siz[ru] + siz[rv];
			par[ru] = rv;
		}
	}

	bool same(int u, int v) {
		if (root(u) == root(v)) {
			return true;
		}
		return false;
	}
};


int main() {
	while (true) {
		int n;
		cin >> n;
		if (n == 0) {
			break;
		}
		vector<point> coordinate(n);
		vector<double> r(n);
		rep(i, n) {
			cin >> coordinate[i].x >> coordinate[i].y >> coordinate[i].z >> r[i];
		}

		vector<tuple<double, int, int>> edge;

		rep(i, n) {
			rep(j, n) {
				if (i != j) {
					double dist = calc(coordinate[i], coordinate[j]);
					if (r[i] + r[j] >= dist) {
						edge.emplace_back(0.0, i, j);
					}
					else {
						edge.emplace_back(dist-(r[i]+r[j]), i, j);
					}
				}
			}
		}

		sort(edge.begin(), edge.end());

		UnionFind uf;
		uf.init(n);

		double ans = 0;
		rep(i, edge.size()) {
			auto [dis, from, to] = edge[i];
			if (uf.same(from, to)) {
				continue;
			}
			uf.unite(from, to);
			//cout << dis << endl;
			ans += dis;
		}

		printf("%.3f\n", ans);
	}
}
accuracy: 1
time_ms: 10
memory_kb: 3720
final_rank: 7