#include <bits/stdc++.h>
using namespace std;
template <typename A, typename B>
inline void chmin(A &a, B b) {
  if (a > b) a = b;
}
template <typename A, typename B>
inline void chmax(A &a, B b) {
  if (a < b) a = b;
}
struct UnionFindTree {
  vector<long long> par, sz;
  UnionFindTree(long long n) {
    par.resize(n);
    sz.resize(n);
    for (long long i = 0; i < n; i++) {
      par[i] = i;
      sz[i] = 1;
    }
  }
  long long find(long long x) {
    return x == par[x] ? x : par[x] = find(par[x]);
  }
  void unite(long long x, long long y) {
    x = find(x);
    y = find(y);
    if (x == y) return;
    if (sz[x] < sz[y]) swap(x, y);
    sz[x] += sz[y];
    par[y] = x;
  }
  bool areSame(long long x, long long y) { return find(x) == find(y); }
  long long size(long long x) { return sz[find(x)]; }
};
long long N;
char str[1111111];
long long itr;
long long rd() {
  long long ret = 0;
  while (isdigit(str[itr])) ret = ret * 10 + str[itr++] - '0';
  return ret;
}
vector<vector<long long> > G[1111];
long long sz[1111];
vector<long long> g[1111];
void dfs(long long v, long long p, vector<long long> &a) {
  a.push_back(v);
  for (auto u : g[v]) {
    if (u != p) dfs(u, v, a);
  }
}
signed main() {
  scanf("%lld", &N);
  for (long long i = 0; i < (N); i++) {
    scanf("%s", str);
    itr = 0;
    long long l = strlen(str);
    str[l] = '-';
    l++;
    while (itr < l) {
      long long k = rd();
      itr++;
      vector<long long> v;
      for (long long t = 0; t < (k); t++) {
        v.push_back(rd() - 1);
        itr++;
      }
      G[i].push_back(v);
    }
  }
  fill_n(sz, N, 1);
  vector<pair<long long, long long> > lis[1111];
  for (long long i = 0; i < (N); i++) {
    for (long long j = 0; j < (G[i].size()); j++) {
      if (G[i][j].size() <= N / 2) lis[G[i][j].size()].push_back({i, j});
    }
  }
  UnionFindTree uf(N);
  vector<pair<long long, long long> > ans;
  for (long long i = 1; i < (N + 1) / 2; i++) {
    for (auto &w : lis[i]) {
      long long v = w.first;
      vector<long long> &a = G[v][w.second];
      for (auto &u : a)
        if (!uf.areSame(a[0], u)) {
          cout << -1 << endl;
          return 0;
        }
      long long y = -1;
      for (auto &u : a) {
        if (sz[u] == i) y = u;
      }
      if (y == -1 || uf.areSame(v, y)) {
        cout << -1 << endl;
        return 0;
      }
      ans.push_back({v, y});
      sz[v] += sz[y];
      uf.unite(v, y);
    }
  }
  if (N % 2 == 0 && lis[N / 2].size() == 2) {
    long long x = lis[N / 2][0].first;
    long long y = lis[N / 2][1].first;
    if (uf.areSame(x, y)) {
      cout << -1 << endl;
      return 0;
    }
    uf.areSame(x, y);
    ans.push_back({x, y});
  }
  if (ans.size() != N - 1) {
    cout << -1 << endl;
    return -1;
  }
  for (long long i = 0; i < (N - 1); i++)
    g[ans[i].first].push_back(ans[i].second),
        g[ans[i].second].push_back(ans[i].first);
  for (long long i = 0; i < (N); i++) {
    vector<vector<long long> > x;
    for (auto &v : g[i]) {
      vector<long long> a;
      dfs(v, i, a);
      sort((a).begin(), (a).end());
      x.push_back(a);
    }
    sort((x).begin(), (x).end());
    for (long long j = 0; j < (G[i].size()); j++)
      sort((G[i][j]).begin(), (G[i][j]).end());
    sort((G[i]).begin(), (G[i]).end());
    if (G[i] != x) {
      cout << -1 << endl;
      return 0;
    }
  }
  cout << ans.size() << endl;
  for (long long i = 0; i < (ans.size()); i++)
    cout << ans[i].first + 1 << " " << ans[i].second + 1 << endl;
  return 0;
}
