import java.util.*;

class Main {

    static final float PI = 3.14f;

    static float prevX, prevY, prevZ;

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);

        try {
            if (!sc.hasNextInt()) {
                System.out.print("Invalid input.");
                return;
            }

            int N = sc.nextInt();
            if (N < 2 || N > 10) {
                System.out.print("Invalid input.");
                return;
            }

            float[] arr = new float[3 * N];

            for (int i = 0; i < 3 * N; i++) {
                if (!sc.hasNextFloat()) {
                    System.out.print("Invalid input.");
                    return;
                }

                arr[i] = sc.nextFloat();

                // Check valid coordinate range
                if (arr[i] < 0 || arr[i] > 10) {
                    System.out.print("Invalid input.");
                    return;
                }

                // z must not be 0 (no bottom face)
                if (i % 3 == 2 && arr[i] == 0) {
                    System.out.print("Invalid input.");
                    return;
                }

                // No points on cube edges => cannot have 0 or 10 simultaneously on 2 coordinates
                int mod = i % 3;
                if (mod == 2) { // full point (x,y,z) available
                    float x = arr[i - 2];
                    float y = arr[i - 1];
                    float z = arr[i];

                    if (onEdge(x, y, z)) {
                        System.out.print("Invalid input.");
                        return;
                    }
                }
            }

            prevX = arr[0];
            prevY = arr[1];
            prevZ = arr[2];

            float total = 0.0f;

            for (int i = 3; i < 3 * N; i += 3) {
                float x = arr[i];
                float y = arr[i + 1];
                float z = arr[i + 2];

                float d = computeDistance(x, y, z);
                if (d < 0) {
                    System.out.print("Invalid input.");
                    return;
                }

                // Round each hop
                total += Math.round(d * 100.0f) / 100.0f;

                prevX = x;
                prevY = y;
                prevZ = z;
            }

            System.out.printf("%.2f", total);

        } catch (Exception e) {
            System.out.print("Invalid input.");
        }
    }

    // Check if a point lies on cube edges
    private static boolean onEdge(float x, float y, float z) {
        int count10 = 0, count0 = 0;

        if (x == 0 || x == 10) count10++;
        if (y == 0 || y == 10) count10++;
        if (z == 0 || z == 10) count10++;

        return (count10 >= 2); // On an edge
    }

    // Computes distance between previous and next point
    private static float computeDistance(float x, float y, float z) {

        // SAME FACE => circular arc of 60 degrees (1/6 of circumference)
        if (prevZ == z && (prevX == x || prevY == y)) {

            float diff = (prevX != x) ? Math.abs(x - prevX) : Math.abs(y - prevY);
            return (2 * PI * diff) / 6.0f;  // arc length = circle * 1/6
        }

        // Cannot travel along bottom
        if (prevZ == 0 || z == 0) return -1;

        // DIFFERENT FACE => shortest path on cube’s surface (unfolded approximation)
        float dx = Math.abs(x - prevX);
        float dy = Math.abs(y - prevY);
        float dz = Math.abs(z - prevZ);

        return (float) (Math.sqrt(dx * dx + dy * dy) + dz);
    }
}
