#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
bitset<N> G[N], G2[N], T;
int tree[N], ecnt;
set<pair<int, int> > ans;
inline void adde(int from, int to) {
  if (from > to) swap(from, to);
  if (ans.count(pair<int, int>(from, to))) return;
  ecnt++, ans.insert(pair<int, int>(from, to));
}
int main() {
  int n;
  scanf("%d", &n);
  if (n == 2) return puts("1 2"), 0;
  for (int i = 1; i <= n; i++) {
    int k;
    scanf("%d", &k), G2[i][i] = 1;
    for (int j = 1; j <= k; j++) {
      int a;
      scanf("%d", &a);
      G[i][a] = 1;
    }
  }
  for (int i = 1; i <= n; i++)
    for (int j = i + 1; j <= n; j++) {
      auto v = G[i] & G[j];
      if (v.count() != 2) continue;
      int a = 0, b = 0;
      for (int k = 1; k <= n; k++)
        if (v[k]) {
          if (!a)
            a = k;
          else
            b = k;
        }
      adde(a, b), G2[a][b] = G2[b][a] = 1;
      tree[a] = tree[b] = 1, T[a] = T[b] = 1;
    }
  if (!ecnt) {
    for (int i = 2; i <= n; i++) printf("1 %d\n", i);
    return 0;
  }
  if (ecnt == 1) {
    int u = ans.begin()->first, v = ans.begin()->second;
    bitset<N> L, R;
    int t = 0;
    for (int i = 1; i <= n; i++)
      if (G[i].count() != n) {
        if (!t)
          L = G[i];
        else if (G[i] != L)
          R = G[i];
      }
    printf("%d %d\n", u, v);
    for (int i = 1; i <= n; i++)
      if (i != u && i != v) {
        if (L[i])
          printf("%d %d\n", u, i);
        else
          printf("%d %d\n", v, i);
      }
    return 0;
  }
  for (int i = 1; i <= n; i++)
    if (!tree[i]) {
      int at = 0, mn = 1e9;
      for (int j = 1; j <= n; j++)
        if (G[j][i] && G[j].count() < mn) mn = G[j].count(), at = j;
      auto tmp = G[at] & T;
      for (int j = 1; j <= n; j++)
        if (tree[j] && G2[j] == tmp) {
          adde(i, j);
          break;
        }
    }
  for (auto ed : ans) printf("%d %d\n", ed.first, ed.second);
  return 0;
}
