// Arup Guha
// 4/1/2014
// Solution to 2014 Chicago Invitational (NAIPC) Problem I: Super Mario 169

import java.util.*;
import java.io.*;

public class i {

	public static void main(String[] args)  {

		Scanner stdin = new Scanner(System.in);
		int n = stdin.nextInt();
		int x = stdin.nextInt();
		int y = stdin.nextInt();
		int z = stdin.nextInt();

		// Go through each case.
		while (n != 0) {

			// Set this up.
			pt start = new pt(x,y,z);
			set[] all = new set[n];
			pt[] allStarts = new pt[n];

			// Lots of annoying reading...
			for (int i=0; i<n; i++) {
				int k = stdin.nextInt();
				x = stdin.nextInt();
				y = stdin.nextInt();
				z = stdin.nextInt();
				allStarts[i] = new pt(x,y,z);
				pt[] coins = new pt[k];
				for (int j=0; j<k; j++) {
					x = stdin.nextInt();
					y = stdin.nextInt();
					z = stdin.nextInt();
					coins[j] = new pt(x,y,z);
				}

				// Create object.
				all[i] = new set(allStarts[i], coins);
			}

			// Solve small traveling salesmen instances.
			double[][] distArray = new double[n][];
			for (int i=0; i<n; i++)
				distArray[i] = all[i].minDist();

			// Use small instances to solve shortest distance from one start switch to the next start switch.
			double[][] d2Array = new double[n][n];
			for (int i=0; i<n; i++) {
				for (int j=0; j<n; j++) {
					if (i == j) continue;

					// Try linking from each ending coin in set i to the switch in set j.
					double best = 1e10;
					for (int k=0; k<distArray[i].length; k++)
						best = Math.min(best, distArray[i][k] + all[i].coins[k].dist(all[j].start));

					// Store best.
					d2Array[i][j] = best;
				}
			}

			// Solve large instance - wish I could reuse code :(
			System.out.printf("%.2f\n", travsales(start, all, distArray, d2Array));

			// Get next set.
			n = stdin.nextInt();
			x = stdin.nextInt();
			y = stdin.nextInt();
			z = stdin.nextInt();
		}

	}

	// Solves outer Traveling Salesman Instance.
	public static double travsales(pt start, set[] all, double[][] distArray, double[][] d2Array) {

		int n = distArray.length;

		double[][] dp = new double[1<<n][n];

		// De ja vu...
		for (int i=1; i<dp.length; i++) {

			// See if bit j is on.
			for (int j=0; j<n; j++) {

				// Need to store a whole array for each subset, ending pair.
				double best = 1e10;

				if ((i & (1 << j)) > 0) {

					int prev = i - (1 << j);

					// Base case.
					if (prev == 0) best = start.dist(all[j].start);

					else {

						// Try each spot before getting to j.
						for (int k=0; k<n; k++) {
							if ((prev & (1 << k)) > 0) {

								// Take best results.
								double tmp = dp[prev][k] + d2Array[k][j];
								if (tmp < best) best = tmp;
							}
						}
					}
				}

				// Store results.
				dp[i][j] = best;
			}
		}

		// Get final answer!
		double finalAns = 1e10;
		for (int i=0; i<n; i++)
			if (dp[(1<<n)-1][i] + minimum(distArray[i]) < finalAns)
					finalAns = dp[(1<<n)-1][i] + minimum(distArray[i]);

		return finalAns;
	}

	public static double minimum(double[] array) {
		double ans = array[0];
		for (int i=0; i<array.length; i++)
			ans = Math.min(ans, array[i]);
		return ans;
	}

	// Adds offset to each element of array and returns this new array. array is left unchanged.
	public static double[] getArray(double offset, double[] array) {
		double[] ans = new double[array.length];
		for (int i=0; i<array.length; i++)
			ans[i] = array[i] + offset;
		return ans;
	}


	// Both arrays must be same length. Stores mins at each spot into best.
	public static void merge(double[] best, double[] other) {
		for (int i=0; i<best.length; i++)
			best[i] = Math.min(best[i], other[i]);
	}
}

class pt {

	public int x;
	public int y;
	public int z;

	public pt(int myx, int myy, int myz) {
		x = myx;
		y = myy;
		z = myz;
	}

	public double dist(pt other) {
		return Math.sqrt((x-other.x)*(x-other.x) + (y-other.y)*(y-other.y)+ (z-other.z)*(z-other.z));
	}
}

class set {

	public pt start;
	public pt[] coins;

	public set(pt myStart, pt[] myCoins) {
		start = myStart;
		coins = myCoins;
	}

	public double[] minDist() {

		int n = coins.length;
		double[][] dp = new double[1<<n][n];

		// Run traveling salesman DP.
		for (int i=1; i<dp.length; i++) {

			// See if bit j is on.
			for (int j=0; j<n; j++) {

				double best = 1e10;
				if ((i & (1 << j)) > 0) {

					int prev = i - (1 << j);

					// Base case.
					if (prev == 0) best = start.dist(coins[j]);

					// Standard case.
					else {

						// Try to build off each previous spot before j, to get to j.
						for (int k=0; k<n; k++) {
							if ((prev & (1 << k)) > 0) {
								double tmp = dp[i-(1<<j)][k] + coins[k].dist(coins[j]);
								if (tmp < best) best = tmp;
							}
						}
					}
				}

				// Set this element.
				dp[i][j] = best;
			}
		} // end i

		// Final values.
		return dp[(1<<n) - 1];
	}
}