description: This is the easy version of the problem. The only difference between the two versions is the constraint on n. You can make hacks only if all versions of the problem are solved.
  
  A forest is an undirected graph without cycles (not necessarily connected).
  
  Mocha and Diana are friends in Zhijiang, both of them have a forest with nodes numbered from 1 to n, and they would like to add edges to their forests such that: 
  
    * After adding edges, both of their graphs are still forests. 
    * They add the same edges. That is, if an edge (u, v) is added to Mocha's forest, then an edge (u, v) is added to Diana's forest, and vice versa. 
  
  
  
  Mocha and Diana want to know the maximum number of edges they can add, and which edges to add.
  
  Input
  
  The first line contains three integers n, m_1 and m_2 (1 ≤ n ≤ 1000, 0 ≤ m_1, m_2 < n) — the number of nodes and the number of initial edges in Mocha's forest and Diana's forest.
  
  Each of the next m_1 lines contains two integers u and v (1 ≤ u, v ≤ n, u ≠ v) — the edges in Mocha's forest.
  
  Each of the next m_2 lines contains two integers u and v (1 ≤ u, v ≤ n, u ≠ v) — the edges in Diana's forest.
  
  Output
  
  The first line contains only one integer h, the maximum number of edges Mocha and Diana can add (in each forest).
  
  Each of the next h lines contains two integers u and v (1 ≤ u, v ≤ n, u ≠ v) — the edge you add each time.
  
  If there are multiple correct answers, you can print any one of them.
  
  Examples
  
  Input
  
  
  3 2 2
  1 2
  2 3
  1 2
  1 3
  
  
  Output
  
  
  0
  
  
  Input
  
  
  5 3 2
  5 4
  2 1
  4 3
  4 3
  1 4
  
  
  Output
  
  
  1
  2 4
  
  
  Input
  
  
  8 1 2
  1 7
  2 6
  1 5
  
  
  Output
  
  
  5
  5 2
  2 3
  3 4
  4 7
  6 8
  
  Note
  
  In the first example, we cannot add any edge.
  
  In the second example, the initial forests are as follows.
  
  <image>
  
  We can add an edge (2, 4).
  
  <image>
solution: import java.io.*;
  import java.util.*;
  
  public class Solution2 {
      static FastScanner fs;
      static PrintWriter pw;
      public static void main(String[] args) {
          fs = new FastScanner();
          pw = new PrintWriter(System.out);
          precomp();
  //        int t = fs.nextInt();
  //        while (t-- > 0)
              solve();
          pw.close();
      }
      public static void precomp() {
      }
      public static void solve() {
          int n = fs.nextInt();
          int m1 = fs.nextInt();
          int m2 = fs.nextInt();
  //        HashMap<Integer, ArrayList<Integer>> graph1 = new HashMap<>();
  //        HashMap<Integer, ArrayList<Integer>> graph2 = new HashMap<>();
          DisjointSets dsu1 = new DisjointSets(n);
          DisjointSets dsu2 = new DisjointSets(n);
          for (int i=0 ; i<m1; i++) {
              int u = fs.nextInt()-1;
              int v = fs.nextInt()-1;
  //            graph1.get(u).add(v);
  //            graph1.get(v).add(u);
              dsu1.union(u, v);
          }
          for (int i=0 ; i<m2; i++) {
              int u = fs.nextInt()-1;
              int v = fs.nextInt()-1;
  //            graph2.get(u).add(v);
  //            graph2.get(v).add(u);
              dsu2.union(u, v);
          }
          ArrayList<int[]> ans = new ArrayList<>();
          for (int i=0; i<n; i++) {
              for (int j=i+1; j<n; j++) {
                  if (!dsu1.connected(i, j)) {
                      if (dsu2.union(i, j)) {
                          dsu1.union(i, j);
                          ans.add(new int[]{i+1, j+1});
                      }
                  }
              }
          }
          pw.println(ans.size());
          for (int i=0; i<ans.size(); i++) {
              pw.println(ans.get(i)[0]+" "+ans.get(i)[1]);
          }
  
      }
      static long pow(long b, long exp, long mod) {
          long ret = 1;
          while (exp > 0) {
              if ((exp & 1) > 0)
                  ret = (ret * b) % mod;
              b = (b * b) % mod;
              exp >>= 1;
          }
          return ret;
      }
  
      static int nCrmod(int n, int r, int mod) {
          if (r > n)
              return 0;
          if (n - r > r)
              r = n - r;
          int[] SPF = new int[n + 1];
          for (int i = 1; i <= n; i++)
              SPF[i] = i;
          for (int i = 4; i <= n; i += 2)
              SPF[i] = 2;
          for (int i = 3; i * i < n + 1; i += 2) {
              if (SPF[i] == i) {
                  for (int j = i * i; j < n + 1; j += i)
                      if (SPF[j] == j) {
                          SPF[j] = i;
                      }
              }
          }
          Map<Integer, Integer> prime_pow = new HashMap<>();
          for (int i = r + 1; i < n + 1; i++) {
              int t = i;
              while (t > 1) {
                  prime_pow.put(SPF[t],
                          prime_pow.getOrDefault(SPF[t], 0) + 1);
                  t /= SPF[t];
              }
          }
          for (int i = 1; i < n - r + 1; i++) {
              int t = i;
              while (t > 1) {
                  prime_pow.put(SPF[t], prime_pow.get(SPF[t]) - 1);
                  t /= SPF[t];
              }
          }
          long ans = 1;
          for (int i : prime_pow.keySet())
              ans = (ans * pow(i, prime_pow.get(i), mod)) % mod;
          return (int) ans;
      }
  
      //    static int k;
  //    static int par(int curr) {
  //        return (1<<k)-1-(((1<<k)-1-curr)/2);
  //    }
  //    static int left(int curr) {
  //        return (1<<k)-1-(2*((1<<k)-1-curr)+1);
  //    }
  //    static int right(int curr) {
  //        return (1<<k)-1-(2*((1<<k)-1-curr));
  //    }
      static int gcd(int a, int b) {
          if (a == 0) return b;
          return gcd(b % a, a);
      }
  
      static void ruffleSort(int[] a) {
          int n = a.length;//shuffle, then sort
          for (int i = 0; i < n; i++) {
              int oi = random.nextInt(n), temp = a[oi];
              a[oi] = a[i];
              a[i] = temp;
          }
          Arrays.sort(a);
      }
  
      static final Random random = new Random();
  
      static class FastScanner {
          BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
          StringTokenizer st = new StringTokenizer("");
  
          String next() {
              while (!st.hasMoreTokens())
                  try {
                      st = new StringTokenizer(br.readLine());
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              return st.nextToken();
          }
  
          int nextInt() {
              return Integer.parseInt(next());
          }
  
          int[] readArray(int n) {
              int[] a = new int[n];
              for (int i = 0; i < n; i++) a[i] = nextInt();
              return a;
          }
  
          long nextLong() {
              return Long.parseLong(next());
          }
      }
  
      static int[] reverse(int[] a) {
          int n = a.length;
          int[] res = new int[n];
          for (int i = 0; i < n; i++) res[i] = a[n - 1 - i];
          return res;
      }
      static class Node {
          int sum;
          int min;
          //Here We store the value that will be propagated lazily
          Integer pendingVal = null;
          int from;
          int to;
  
          int size() {
              return to - from + 1;
          }
  
      }
      static class SegmentTree {
  
          private Node[] heap;
          private int[] array;
          private int size;
  
          /**
           * Time-Complexity:  O(n*log(n))
           *
           * @param array the Initialization array
           */
          public SegmentTree(int[] array) {
              this.array = Arrays.copyOf(array, array.length);
              //The max size of this array is about 2 * 2 ^ log2(n) + 1
              size = (int) (2 * Math.pow(2.0, Math.floor((Math.log((double) array.length) / Math.log(2.0)) + 1)));
              heap = new Node[size];
              build(1, 0, array.length);
          }
  
  
          public int size() {
              return array.length;
          }
  
          //Initialize the Nodes of the Segment tree
          private void build(int v, int from, int size) {
              heap[v] = new Node();
              heap[v].from = from;
              heap[v].to = from + size - 1;
  
              if (size == 1) {
                  heap[v].sum = array[from];
                  heap[v].min = array[from];
              } else {
                  //Build childs
                  build(2 * v, from, size / 2);
                  build(2 * v + 1, from + size / 2, size - size / 2);
  
                  heap[v].sum = heap[2 * v].sum + heap[2 * v + 1].sum;
                  //min = min of the children
                  heap[v].min = Math.min(heap[2 * v].min, heap[2 * v + 1].min);
              }
          }
  
          /**
           * Range Sum Query
           *
           * Time-Complexity: O(log(n))
           *
           * @param  from from index
           * @param  to to index
           * @return sum
           */
          public int rsq(int from, int to) {
              return rsq(1, from, to);
          }
  
          private int rsq(int v, int from, int to) {
              Node n = heap[v];
  
              //If you did a range update that contained this node, you can infer the Sum without going down the tree
              if (n.pendingVal != null && contains(n.from, n.to, from, to)) {
                  return (to - from + 1) * n.pendingVal;
              }
  
              if (contains(from, to, n.from, n.to)) {
                  return heap[v].sum;
              }
  
              if (intersects(from, to, n.from, n.to)) {
                  propagate(v);
                  int leftSum = rsq(2 * v, from, to);
                  int rightSum = rsq(2 * v + 1, from, to);
  
                  return leftSum + rightSum;
              }
  
              return 0;
          }
  
          /**
           * Range Min Query
           *
           * Time-Complexity: O(log(n))
           *
           * @param  from from index
           * @param  to to index
           * @return min
           */
          public int rMinQ(int from, int to) {
              return rMinQ(1, from, to);
          }
  
          private int rMinQ(int v, int from, int to) {
              Node n = heap[v];
  
  
              //If you did a range update that contained this node, you can infer the Min value without going down the tree
              if (n.pendingVal != null && contains(n.from, n.to, from, to)) {
                  return n.pendingVal;
              }
  
              if (contains(from, to, n.from, n.to)) {
                  return heap[v].min;
              }
  
              if (intersects(from, to, n.from, n.to)) {
                  propagate(v);
                  int leftMin = rMinQ(2 * v, from, to);
                  int rightMin = rMinQ(2 * v + 1, from, to);
  
                  return Math.min(leftMin, rightMin);
              }
  
              return Integer.MAX_VALUE;
          }
  
  
          /**
           * Range Update Operation.
           * With this operation you can update either one position or a range of positions with a given number.
           * The update operations will update the less it can to update the whole range (Lazy Propagation).
           * The values will be propagated lazily from top to bottom of the segment tree.
           * This behavior is really useful for updates on portions of the array
           * <p>
           * Time-Complexity: O(log(n))
           *
           * @param from  from index
           * @param to    to index
           * @param value value
           */
          public void update(int from, int to, int value) {
              update(1, from, to, value);
          }
  
          private void update(int v, int from, int to, int value) {
  
              //The Node of the heap tree represents a range of the array with bounds: [n.from, n.to]
              Node n = heap[v];
  
              /**
               * If the updating-range contains the portion of the current Node  We lazily update it.
               * This means We do NOT update each position of the vector, but update only some temporal
               * values into the Node; such values into the Node will be propagated down to its children only when they need to.
               */
              if (contains(from, to, n.from, n.to)) {
                  change(n, value);
              }
  
              if (n.size() == 1) return;
  
              if (intersects(from, to, n.from, n.to)) {
                  /**
                   * Before keeping going down to the tree We need to propagate the
                   * the values that have been temporally/lazily saved into this Node to its children
                   * So that when We visit them the values  are properly updated
                   */
                  propagate(v);
  
                  update(2 * v, from, to, value);
                  update(2 * v + 1, from, to, value);
  
                  n.sum = heap[2 * v].sum + heap[2 * v + 1].sum;
                  n.min = Math.min(heap[2 * v].min, heap[2 * v + 1].min);
              }
          }
  
          //Propagate temporal values to children
          private void propagate(int v) {
              Node n = heap[v];
  
              if (n.pendingVal != null) {
                  change(heap[2 * v], n.pendingVal);
                  change(heap[2 * v + 1], n.pendingVal);
                  n.pendingVal = null; //unset the pending propagation value
              }
          }
  
          //Save the temporal values that will be propagated lazily
          private void change(Node n, int value) {
              n.pendingVal = value;
              n.sum = n.size() * value;
              n.min = value;
              array[n.from] = value;
  
          }
  
          //Test if the range1 contains range2
          private boolean contains(int from1, int to1, int from2, int to2) {
              return from2 >= from1 && to2 <= to1;
          }
          //check inclusive intersection, test if range1[from1, to1] intersects range2[from2, to2]
          private boolean intersects(int from1, int to1, int from2, int to2) {
              return from1 <= from2 && to1 >= from2   //  (.[..)..] or (.[...]..)
                      || from1 >= from2 && from1 <= to2; // [.(..]..) or [..(..)..
          }
      }
      public static class DisjointSets {
          int[] parents;  // 0-indexed
          int[] sizes;
          public DisjointSets(int size) {
              sizes = new int[size];
              parents = new int[size];
              Arrays.fill(sizes, 1);
              Arrays.fill(parents, -1);
          }
  
          // finds the "representative" node in a's component
          public int find(int x) {
              return parents[x] == -1 ? x : (parents[x] = find(parents[x]));
          }
  
          // returns whether the merge changed connectivity
          public boolean union(int x, int y) {
              int xRoot = find(x);
              int yRoot = find(y);
              if (xRoot == yRoot) {
                  return false;
              }
              if (sizes[xRoot] < sizes[yRoot]) {
                  parents[xRoot] = yRoot;
                  sizes[yRoot] += sizes[xRoot];
              } else {
                  parents[yRoot] = xRoot;
                  sizes[xRoot] += sizes[yRoot];
              }
              return true;
          }
  
          // returns whether two nodes are in the same connected component
          public boolean connected(int x, int y) {
              return find(x) == find(y);
          }
      }
  
  }