#include <bits/stdc++.h>
using namespace std;
vector<list<set<int>>> lst;
vector<vector<int>> g;
bool digit(char c) { return '0' <= c && c <= '9'; }
int readInt(const string &s, int &pos) {
  int ret = 0;
  for (; !(pos == (int((s).size())) || !digit(s[pos])); pos++) {
    ret = ret * 10 + s[pos] - '0';
  }
  return ret;
}
unsigned long long P[1001];
unsigned long long Hash(int v, int p) {
  unsigned long long ret = P[v];
  for (auto &u : g[v]) {
    if (u == p) continue;
    ret += Hash(u, v);
  }
  return ret;
}
set<unsigned long long> Hashes(int v) {
  set<unsigned long long> ret;
  for (auto &u : g[v]) {
    ret.insert(Hash(u, v));
  }
  return ret;
}
int main(int argc, char *argv[]) {
  ios::sync_with_stdio(0);
  P[0] = 1;
  for (int(i) = (1); (i) < (1001); (i)++) {
    P[i] = P[i - 1] * 31;
  }
  int n;
  cin >> n;
  lst.resize(n);
  g.resize(n);
  vector<vector<list<set<int>>::iterator>> iters(
      n, vector<list<set<int>>::iterator>(n));
  for (int(i) = (0); (i) < (n); (i)++) {
    for (int(j) = (0); (j) < (n); (j)++) {
      iters[i][j] = lst[j].end();
    }
  }
  for (int(i) = (0); (i) < (n); (i)++) {
    string s;
    cin >> s;
    int pos = 0;
    for (; !(pos >= (int((s).size())));) {
      int m = readInt(s, pos);
      lst[i].emplace_back();
      for (int(_) = (0); (_) < (m); (_)++) {
        pos++;
        int tmp = readInt(s, pos);
        tmp--;
        auto it = lst[i].back().insert(tmp);
        iters[tmp][i] = --lst[i].end();
      }
      pos++;
    }
  }
  vector<set<unsigned long long>> input(n);
  for (int(i) = (0); (i) < (n); (i)++) {
    for (auto it = lst[i].begin(); it != lst[i].end(); it++) {
      unsigned long long cur = 0;
      for (auto &k : *it) {
        cur += P[k];
      }
      input[i].insert(cur);
    }
  }
  string used(n, 0);
  string dead(n, 0);
  queue<int> leafs;
  for (int(i) = (0); (i) < (n); (i)++) {
    if ((int((lst[i]).size())) == 1) {
      leafs.push(i);
      used[i] = 1;
    }
  }
  for (int(_) = (0); (_) < (n - 1); (_)++) {
    if (leafs.empty()) {
      cout << "-1" << endl;
      return 0;
    }
    int leaf = leafs.front();
    leafs.pop();
    dead[leaf] = 1;
    for (int(i) = (0); (i) < (n); (i)++) {
      if (dead[i]) continue;
      auto it = iters[leaf][i];
      if (it == lst[i].end()) {
        cout << "-1" << endl;
        return 0;
      }
      if (it->size() == 1) {
        g[leaf].push_back(i);
        g[i].push_back(leaf);
      }
      it->erase(leaf);
      if (it->empty()) {
        lst[i].erase(it++);
      } else {
        it++;
      }
      if ((int((lst[i]).size())) == 1) {
        if (!used[i]) {
          leafs.push(i);
          used[i] = 1;
        }
      }
    }
  }
  int cnt = 0;
  for (int(i) = (0); (i) < (n); (i)++) {
    cnt += (int((g[i]).size()));
  }
  cnt /= 2;
  if (cnt != n - 1) {
    cout << -1 << endl;
    return 0;
  }
  vector<set<unsigned long long>> built(n);
  for (int(i) = (0); (i) < (n); (i)++) {
    built[i] = Hashes(i);
  }
  for (int(i) = (0); (i) < (n); (i)++) {
    if (input[i] != built[i]) {
      cout << "-1" << endl;
      return 0;
    }
  }
  cout << n - 1 << endl;
  for (int(i) = (0); (i) < (n); (i)++) {
    for (auto &j : g[i]) {
      if (i < j) {
        cout << i + 1 << " " << j + 1 << endl;
      }
    }
  }
  return 0;
}
