#include <bits/stdc++.h>

using namespace std;

namespace max_flow {

const int max_v = 200222, inf = 1000111222;

struct edge {
    int to, residual_capacity;

    edge(int to, int residual_capacity): to(to), residual_capacity(residual_capacity) {
    }
};

vector<edge> edges;
vector<int> g[max_v];

void add_edge(int u, int v, int capacity) {
    g[u].push_back(edges.size());
    edges.push_back({v, capacity});
    g[v].push_back(edges.size());
    edges.push_back({u, 0});
}

int h[max_v], num[max_v];

bool bfs(int s, int t) {
    for (int i = 0; i <= t; ++i) {
        h[i] = -1;
    }
    h[s] = 0;
    queue<int> q;
    q.push(s);
    while (!q.empty()) {
        int v = q.front();
        q.pop();
        for (int id : g[v]) {
            if (edges[id].residual_capacity && h[edges[id].to] == -1) {
                h[edges[id].to] = h[v] + 1;
                q.push(edges[id].to);
            }
        }
    }
    return h[t] != -1;
}

int dfs(int v, int t, int f) {
    if (v == t) {
        return f;
    }
    for (int &i = num[v]; i < g[v].size(); ++i) {
        const int id = g[v][i];
        if (edges[id].residual_capacity && h[v] + 1 == h[edges[id].to]) {
            int res = dfs(edges[id].to, t, min(f, edges[id].residual_capacity));
            if (res) {
                edges[id].residual_capacity -= res;
                edges[id ^ 1].residual_capacity += res;
                return res;
            }
        }
    }
    return 0;
}

int dinic(int s, int t) {
    int res = 0;
    while (bfs(s, t)) {
        memset(num, 0, sizeof(num));
        while (int f = dfs(s, t, inf)) {
            res += f;
        }
    }
    return res;
}

}

const int max_n = 100111, inf = 1000111222;

int n, p[max_n], nxt[max_n], ans[max_n], used[max_n];
vector<int> g[max_n], g2[max_n];

void dfs2(int v) {
    used[v] = 1;
    for (int to : g2[v]) {
        if (used[to] == 0) {
            dfs2(to);
            ans[to] = nxt[v];
        }
    }
}

int main() {
    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
    scanf("%d", &n);
    int s = 2 * n - 1, t = 2 * n;
    for (int i = 0; i + 1 < n; ++i) {
        int k;
        scanf("%d", &k);
        g[i].resize(k);
        for (int &x : g[i]) {
            scanf("%d", &x);
            --x;
        }
    }
    for (int i = 0; i + 1 < n; ++i) {
        max_flow::add_edge(s, i, 1);
        for (int to : g[i]) {
            max_flow::add_edge(i, n - 1 + to, 1);
        }
    }
    for (int i = 0; i < n; ++i) {
        max_flow::add_edge(n - 1 + i, t, 1);
    }
    int f = max_flow::dinic(s, t);
    memset(p, -1, sizeof(p));
    memset(nxt, -1, sizeof(nxt));
    for (int i = 0; i + 1 < n; ++i) {
        for (int id : max_flow::g[i]) {
            const auto &e = max_flow::edges[id];
            if (e.to != s && e.residual_capacity == 0) {
                nxt[i] = e.to - n + 1;
                p[nxt[i]] = i;
            }
        }
    }
    for (int i = 0; i + 1 < n; ++i) {
        if (nxt[i] == -1) {
            puts("-1");
            return 0;
        }
    }
    int root;
    for (int i = 0; i < n; ++i) {
        if (p[i] == -1) {
            root = i;
            break;
        }
    }
    p[root] = n - 1;
    nxt[n - 1] = root;
    for (int i = 0; i + 1 < n; ++i) {
        for (int to : g[i]) {
            if (to != nxt[i]) {
                g2[p[to]].push_back(i);
            }
        }
    }
    memset(used, 0, sizeof(used));
    dfs2(n - 1);
    for (int i = 0; i < n; ++i) {
        if (!used[i]) {
            puts("-1");
            return 0;
        }
    }
    for (int i = 0; i + 1 < n; ++i) {
        printf("%d %d\n", nxt[i] + 1, ans[i] + 1);
    }
    return 0;
}


Measured memory_bytes: 38120