The Dogeforces company has k employees. Each employee, except for lower-level employees, has at least 2 subordinates. Lower-level employees have no subordinates. Each employee, except for the head of the company, has exactly one direct supervisor. The head of the company is a direct or indirect supervisor of all employees. It is known that in Dogeforces, each supervisor receives a salary strictly more than all his subordinates.

The full structure of the company is a secret, but you know the number of lower-level employees and for each pair of lower-level employees, the salary of their common supervisor is known (if there are several such supervisors, then the supervisor with the minimum salary). You have to restore the structure of the company.

Input

The first line contains a single integer n (2 ≤ n ≤ 500) — the number of lower-level employees.

This is followed by n lines, where i-th line contains n integers a_{i,1}, a_{i,2}, ..., a_{i,n} (1 ≤ a_{i,j} ≤ 5000) — salary of the common supervisor of employees with numbers i and j. It is guaranteed that a_{i,j} = a_{j,i}. Note that a_{i,i} is equal to the salary of the i-th employee.

Output

In the first line, print a single integer k — the number of employees in the company.

In the second line, print k integers c_1, c_2, ..., c_k, where c_i is the salary of the employee with the number i.

In the third line, print a single integer r — the number of the employee who is the head of the company.

In the following k-1 lines, print two integers v and u (1 ≤ v, u ≤ k) — the number of the employee and his direct supervisor.

Note that the lower-level employees have numbers from 1 to n, and for the rest of the employees, you have to assign numbers from n+1 to k. If there are several correct company structures, you can print any of them.

Example

Input


3
2 5 7
5 1 7
7 7 4


Output


5
2 1 4 7 5 
4
1 5
2 5
5 4
3 4

Note

One of the possible structures in the first example: <image>
import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Comparator;

public class Main {

    private static int result_count;
    private static Result[] results;

    private static void run() throws IOException {
        int n = in.nextInt();
        Node[] nodes = new Node[n * (n - 1) / 2];
        result_count = 0;
        results = new Result[1000];

        int index = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                int now = in.nextInt();
                if (j > i) {
                    nodes[index++] = new Node(i, j, now);
                } else if (i == j) {
                    results[result_count++] = new Result(i, now);
                }
            }
        }
        Arrays.sort(nodes, Comparator.comparingInt((Node o) -> o.value).thenComparingInt(o -> o.x));

        for (Node now : nodes) {
            link(now.x, now.y, now.value);
        }
        out.println(result_count);
        int head = -1;
        for (int i = 0; i < result_count; i++) {
            out.printf("%d ", results[i].value);
            if (i == results[i].father) {
                head = i;
            }
        }
        out.println();
        out.println(head + 1);
        boolean[] visited = new boolean[result_count];
        for (int i = 0; i < result_count; i++) {
            int now = i;
            while (!visited[now]) {
                visited[now] = true;
                int next = results[now].father;
                if (now != next) {
                    out.printf("%d %d\n", now + 1, next + 1);
                }
                now = next;
            }
        }
    }

    private static void link(int x, int y, int value) {
        Result f_x = getFather(x);
        Result f_y = getFather(y);
        if (f_x.value == value && f_y.value == value) {
            return;
        }
        Result bigger = f_x.value > f_y.value ? f_x : f_y;
        Result smaller = f_x.value > f_y.value ? f_y : f_x;
        if (bigger.value == value) {
            smaller.father = bigger.index;
        } else {
            results[result_count] = new Result(result_count, value);
            f_x.father = result_count;
            f_y.father = result_count;
            result_count++;
        }
    }

    private static Result getFather(int x) {
        int now = x;
        while (results[now].father != now) {
            now = results[now].father;
        }
        return results[now];
    }

    static class Result {
        int index, value, father;

        public Result(int index, int value) {
            this.index = index;
            this.value = value;
            this.father = index;
        }
    }

    static class Node {
        int x, y, value;

        public Node(int x, int y, int value) {
            this.x = x;
            this.y = y;
            this.value = value;
        }
    }

    public static void main(String[] args) throws IOException {
        in = new Reader();
        out = new PrintWriter(new OutputStreamWriter(System.out));

//        int t = in.nextInt();
//        for (int i = 0; i < t; i++) {
//        }
        run();

        out.flush();
        in.close();
        out.close();
    }

    private static int gcd(int a, int b) {
        if (a == 0 || b == 0)
            return 0;
        while (b != 0) {
            int tmp;
            tmp = a % b;
            a = b;
            b = tmp;
        }
        return a;
    }

    static final long mod = 1000000007;

    static long pow_mod(long a, long b) {
        long result = 1;
        while (b != 0) {
            if ((b & 1) != 0) result = (result * a) % mod;
            a = (a * a) % mod;
            b >>= 1;
        }
        return result;
    }

    private static long multiplied_mod(long... longs) {
        long ans = 1;
        for (long now : longs) {
            ans = (ans * now) % mod;
        }
        return ans;
    }

    @SuppressWarnings("FieldCanBeLocal")
    private static Reader in;
    private static PrintWriter out;

    private static void print_array(int[] array) {
        for (int now : array) {
            out.print(now);
            out.print(' ');
        }
        out.println();
    }

    private static void print_array(long[] array) {
        for (long now : array) {
            out.print(now);
            out.print(' ');
        }
        out.println();
    }

    static class Reader {
        private static final int BUFFER_SIZE = 1 << 16;
        private final DataInputStream din;
        private final byte[] buffer;
        private int bufferPointer, bytesRead;

        Reader() {
            din = new DataInputStream(System.in);
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public String readLine() throws IOException {
            final byte[] buf = new byte[1024]; // line length
            int cnt = 0, c;
            while ((c = read()) != -1) {
                if (c == '\n') {
                    break;
                }
                buf[cnt++] = (byte) c;
            }
            return new String(buf, 0, cnt);
        }

        public int nextSign() throws IOException {
            byte c = read();
            while ('+' != c && '-' != c) {
                c = read();
            }
            return '+' == c ? 0 : 1;
        }

        private static boolean isSpaceChar(int c) {
            return !(c >= 33 && c <= 126);
        }

        public int skip() throws IOException {
            int b;
            // noinspection ALL
            while ((b = read()) != -1 && isSpaceChar(b)) {
                ;
            }
            return b;
        }

        public char nc() throws IOException {
            return (char) skip();
        }

        public String next() throws IOException {
            int b = skip();
            final StringBuilder sb = new StringBuilder();
            while (!isSpaceChar(b)) { // when nextLine, (isSpaceChar(b) && b != ' ')
                sb.appendCodePoint(b);
                b = read();
            }
            return sb.toString();
        }

        public int nextInt() throws IOException {
            int ret = 0;
            byte c = read();
            while (c <= ' ') {
                c = read();
            }
            final boolean neg = c == '-';
            if (neg) {
                c = read();
            }
            do {
                ret = ret * 10 + c - '0';
            } while ((c = read()) >= '0' && c <= '9');

            if (neg) {
                return -ret;
            }
            return ret;
        }

        public long nextLong() throws IOException {
            long ret = 0;
            byte c = read();
            while (c <= ' ') {
                c = read();
            }
            final boolean neg = c == '-';
            if (neg) {
                c = read();
            }
            do {
                ret = ret * 10 + c - '0';
            }
            while ((c = read()) >= '0' && c <= '9');
            if (neg) {
                return -ret;
            }
            return ret;
        }

        public double nextDouble() throws IOException {
            double ret = 0, div = 1;
            byte c = read();
            while (c <= ' ') {
                c = read();
            }
            final boolean neg = c == '-';
            if (neg) {
                c = read();
            }

            do {
                ret = ret * 10 + c - '0';
            }
            while ((c = read()) >= '0' && c <= '9');

            if (c == '.') {
                while ((c = read()) >= '0' && c <= '9') {
                    ret += (c - '0') / (div *= 10);
                }
            }

            if (neg) {
                return -ret;
            }
            return ret;
        }

        private void fillBuffer() throws IOException {
            bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);
            if (bytesRead == -1) {
                buffer[0] = -1;
            }
        }

        private byte read() throws IOException {
            if (bufferPointer == bytesRead) {
                fillBuffer();
            }
            return buffer[bufferPointer++];
        }

        public void close() throws IOException {
            din.close();
        }

    }
}