import java.io.*;
import java.util.*;

/**
 * Solution for NEERC'2013 Problem T:
 * This solution checks correctness of the input.
 *
 * @author Roman Elizarov
 */
public class dictionary_re {

    private static final int MAX_N = 50;
    private static final int MAX_LEN = 10;

    public static void main(String[] args) throws Exception {
        new dictionary_re().go();
    }

    void go() throws Exception {
        long time = System.currentTimeMillis();
        read();
        solve();
        write();
        System.out.printf("Done in %d ms%n", System.currentTimeMillis() - time);
    }

    int n;
    String[] word;

    void read() throws Exception {
        Scanner in = new Scanner(new File("dictionary.in"));
        n = in.nextInt();
        in.nextLine();
        assert n >= 1 && n <= MAX_N;
        Set<String> wordSet = new HashSet<>();
        word = new String[n];
        for (int i = 0; i < n; i++) {
            word[i] = in.next();
            in.nextLine();
            assert word[i].length() > 0 && word[i].length() <= MAX_LEN;
            assert wordSet.add(word[i]);
            for (int j = 0; j < word[i].length(); j++) {
                char c = word[i].charAt(j);
                assert c >= 'a' && c <= 'z';
            }
        }
        in.close();
    }

    abstract static class Edge {
        final int u;
        final int v;
        final int weight;

        Edge(int u, int v, int weight) {
            this.u = u;
            this.v = v;
            this.weight = weight;
        }
    }

    static class Edge0 extends Edge {
        final char letter;
        final String u0;
        final String v0;

        Edge0(int u, int v, int weight, char letter, String u0, String v0) {
            super(u, v, weight);
            this.letter = letter;
            this.u0 = u0;
            this.v0 = v0;
        }

        @Override
        public String toString() {
            return String.format("%d->%d %d %c ('%s'->'%s')", u, v, weight, letter, u0, v0);
        }
    }

    static class EdgeC extends Edge {
        final int u0;
        final int v0;

        EdgeC(int u, int v, int weight, int u0, int v0) {
            super(u, v, weight);
            this.u0 = u0;
            this.v0 = v0;
        }


        @Override
        public String toString() {
            return String.format("%d->%d %d (%d->%d)", u, v, weight, u0, v0);
        }
    }

    static class GraphMST<E extends Edge> {
        int k;
        List<Map<Integer, E>> e = new ArrayList<>();

        int next() {
            e.add(new HashMap<Integer, E>());
            return k++;
        }

        int[] min;

        int[] stack;
        int top;

        int[] index;
        int num;

        boolean[] inStack;
        int[] low;

        List<E> mst = new ArrayList<>();
        List<List<Integer>> expand = new ArrayList<>();

        List<E> find(int root) {
            // min incoming weights
            min = new int[k];
            Arrays.fill(min, Integer.MAX_VALUE);
            for (Map<Integer, E> edgeMap : e) {
                for (Edge edge : edgeMap.values()) {
                    min[edge.v] = Math.min(min[edge.v], edge.weight);
                }
            }

            // contract cycles via dfs and build mst list
            stack = new int[k];
            index = new int[k];
            Arrays.fill(index, -1);
            inStack = new boolean[k];
            low = new int[k];

            dfs(root);
            for (int i = 0; i < k; i++)
                if (index[i] < 0)
                    dfs(i);

            // if no cycles -- done
            if (expand.size() == k)
                return mst;

            // build contraction
            assert expand.size() < k;
            GraphMST<EdgeC> gNext = new GraphMST<>();
            for (int i = 0; i < expand.size(); i++)
                gNext.next();
            for (int i = 0; i < expand.size(); i++) {
                List<Integer> ei = expand.get(i);
                for (int j = 0; j < expand.size(); j++) {
                    if (j == i)
                        continue;
                    List<Integer> ej = expand.get(j);
                    int w0 = Integer.MAX_VALUE;
                    int u0 = -1;
                    int v0 = -1;
                    for (Integer u : ei) {
                        for (Integer v : ej) {
                            Edge edge = e.get(u).get(v);
                            if (edge != null) {
                                int w = edge.weight - min[v];
                                if (w < w0) {
                                    w0 = w;
                                    u0 = u;
                                    v0 = v;
                                }
                            }
                        }
                    }
                    if (w0 < Integer.MAX_VALUE)
                        gNext.e.get(i).put(j, new EdgeC(i, j, w0, u0, v0));
                }
            }

            // find mst in contracted
            int rootComponent = indexOfComponent(root);
            List<EdgeC> nextMst = gNext.find(rootComponent);

            // restore mst here
            mst.clear();
            spanComponent(root, expand.get(rootComponent));
            for (EdgeC edge : nextMst) {
                mst.add(e.get(edge.u0).get(edge.v0));
                spanComponent(edge.v0, expand.get(edge.v));
            }
            return mst;
        }

        void dfs(int u) {
            index[u] = num++;
            low[u] = index[u];
            stack[top++] = u;
            inStack[u] = true;
            for (E edge : e.get(u).values()) {
                int v = edge.v;
                if (edge.weight > min[v])
                    continue; // not an edge to consider (not min!)
                if (index[v] < 0) {
                    mst.add(edge);
                    dfs(v);
                    low[u] = Math.min(low[u], low[v]);
                    continue;
                }
                if (index[v] < index[u] && inStack[v]) {
                    low[u] = Math.min(low[u], index[v]);
                }
            }
            if (low[u] == index[u]) {
                List<Integer> component = new ArrayList<>();
                int w;
                while (top > 0 && index[stack[top - 1]] >= index[u]) {
                    w = stack[--top];
                    inStack[w] = false;
                    component.add(w);
                }
                Collections.reverse(component); // root of the component at the top
                expand.add(component);
            }
        }

        int indexOfComponent(int u) {
            for (int i = 0; i < expand.size(); i++) {
                List<Integer> component = expand.get(i);
                if (component.contains(u))
                    return i;
            }
            throw new AssertionError();
        }

        void spanComponent(int u, List<Integer> component) {
            HashSet<Integer> compSet = new HashSet<>(component);
            HashSet<Integer> visited = new HashSet<>();
            visited.add(u);
            dfsSpanComponent(u, compSet, visited);
        }

        void dfsSpanComponent(int u, Set<Integer> compSet, Set<Integer> visited) {
            for (E edge : e.get(u).values()) {
                if (edge.weight == min[edge.v] && compSet.contains(edge.v) && !visited.contains(edge.v)) {
                    mst.add(edge);
                    visited.add(edge.v);
                    dfsSpanComponent(edge.v, compSet, visited);
                }
            }
        }
    }

    int m;
    int[] parent;
    char[] letter;

    void solve() {
        GraphMST<Edge0> g = new GraphMST<>();
        Map<String, Integer> nodes = new HashMap<>();
        // nodes
        for (int i = 0; i < n; i++) {
            String w = word[i];
            for (int j = 0; j <= w.length(); j++) {
                String prefix = w.substring(0, j);
                if (!nodes.containsKey(prefix))
                    nodes.put(prefix, g.next());
            }
        }
        // edges
        for (int i = 0; i < n; i++) {
            String w = word[i];
            String up = "";
            for (int j = 1; j <= w.length(); j++) {
                String prefix = w.substring(0, j);
                Integer u = nodes.get(up);
                Integer v = nodes.get(prefix);
                g.e.get(u).put(v, new Edge0(u, v, 1, w.charAt(j - 1), up, prefix));
                for (String otherPrefix : nodes.keySet()) {
                    if (!otherPrefix.equals(prefix) && otherPrefix.endsWith(prefix)) {
                        u = nodes.get(otherPrefix);
                        g.e.get(u).put(v, new Edge0(u, v, 0, '.', otherPrefix, prefix));
                    }
                }
                up = prefix;
            }
        }
        // solve
        List<Edge0> mst = g.find(nodes.get(""));

        // build result tree
        HashMap<String,Integer> s2i = new HashMap<>();
        m = 1;
        s2i.put("", 1); // root
        for (Edge0 edge : mst) {
            assert !s2i.containsKey(edge.v0);
            if (edge.weight == 1)
                s2i.put(edge.v0, ++m);
            else
                s2i.put(edge.v0, s2i.get(edge.u0));
        }

        // find parent & letter
        parent = new int[m + 1];
        letter = new char[m + 1];
        Arrays.fill(parent, -1);
        parent[1] = 0; // root
        for (Edge0 edge : mst) {
            if (edge.weight == 1) {
                parent[s2i.get(edge.v0)] = s2i.get(edge.u0);
                letter[s2i.get(edge.v0)] = edge.letter;
            }
        }
    }

    void write() throws Exception {
        PrintWriter out = new PrintWriter("dictionary.out");
        out.println(m);
        for (int i = 1; i <= m; i++) {
            if (parent[i] <= 0)
                out.println(parent[i]);
            else
                out.println(parent[i] + " " + letter[i]);
        }
        out.close();
    }

//----------------- just for validation ------------------

    /**
     * Strict scanner to verify 100% correspondence between input files and input file format specification.
     * It is a drop-in replacement for {@link java.util.Scanner} that could be added to a solution source
     * (cut-and-paste) without breaking its ability to work with {@link java.util.Scanner}.
     */
    public class Scanner {
        private final BufferedReader in;
        private String line = "";
        private int pos;
        private int lineNo;

        public Scanner(File source) throws FileNotFoundException {
            in = new BufferedReader(new FileReader(source));
            nextLine();
        }

        public void close() {
            assert line == null : "Extra data at the end of file";
            try {
                in.close();
            } catch (IOException e) {
                throw new AssertionError("Failed to close with " + e);
            }
        }

        public void nextLine() {
            assert line != null : "EOF";
            assert pos == line.length() : "Extra characters on line " + lineNo;
            try {
                line = in.readLine();
            } catch (IOException e) {
                throw new AssertionError("Failed to read line with " + e);
            }
            pos = 0;
            lineNo++;
        }

        public String next() {
            assert line != null : "EOF";
            assert line.length() > 0 : "Empty line " + lineNo;
            if (pos == 0)
                assert line.charAt(0) > ' ' : "Line " + lineNo + " starts with whitespace";
            else {
                assert pos < line.length() : "Line " + lineNo + " is over";
                assert line.charAt(pos) == ' ' : "Wrong whitespace on line " + lineNo;
                pos++;
                assert pos < line.length() : "Line " + lineNo + " is over";
                assert line.charAt(pos) > ' ' : "Line " + lineNo + " has double whitespace";
            }
            StringBuilder sb = new StringBuilder();
            while (pos < line.length() && line.charAt(pos) > ' ')
                sb.append(line.charAt(pos++));
            return sb.toString();
        }

        public int nextInt() {
            String s = next();
            assert s.length() == 1 || s.charAt(0) != '0' : "Extra leading zero in number " + s + " on line " + lineNo;
            assert s.charAt(0) != '+' : "Extra leading '+' in number " + s + " on line " + lineNo;
            try {
                return Integer.parseInt(s);
            } catch (NumberFormatException e) {
                throw new AssertionError("Malformed number " + s + " on line " + lineNo);
            }
        }
    }
}
