#include <bits/stdc++.h>

#ifdef HOME
#define db(x) cerr << #x << " = " << x << endl
#define db3(x, y, z) cerr << "(" << #x << ", " << #y << ", " << #z << ") = (" << x << ", " << y << ", " << z << ")" << endl
#define db2(x, y) cerr << "(" << #x << ", " << #y << ") = (" << x << ", " << y << ")" << endl
#define dbv(a) cerr << #a << " = "; for (auto xxx: a) cerr << xxx  << " "; cerr << endl
#else
#define db(x) ;
#define db3(x, y, z) ;
#define db2(x, y) ;
#define dbv(a) ;
#endif

using namespace std;
typedef long long ll;
typedef double dbl;


const int INF = 1.01e9;



struct Edge {
    int to, cap, flow;
};

struct Graph {
    int n;
    vector<vector<int> > e;
    vector<Edge> edges;
    vector<int> d, c;

    Graph() {}
    Graph(int _n) {
        n = _n;
        e.resize(n);
    }

    void addEdge(int from, int to, int cap) {
        e[from].push_back(edges.size());
        edges.push_back(Edge({to, cap, 0}));
        e[to].push_back(edges.size());
        edges.push_back(Edge({from, 0, 0}));
    }

    bool bfs() {
        d.assign(n, INF);
        c.assign(n, 0);
        vector<int> q(n);
        int qL = 0, qR = 0;
        d[0] = 0;
        q[qR++] = 0;
        while (qL < qR) {
            int v = q[qL++];
            for (int i = 0; i < (int)e[v].size(); i++) {
                Edge cur = edges[e[v][i]];
                if (d[cur.to] > d[v] + 1 && cur.flow < cur.cap) {
                    d[cur.to] = d[v] + 1;
                    q[qR++] = cur.to;
                }
            }
        }
        return d[n - 1] != INF;
    }

    int dfs(int v, int flow) {
        if (v == n - 1) return flow;
        if (flow == 0) return 0;
        for (int &i = c[v]; i < (int)e[v].size(); i++) {
            Edge cur = edges[e[v][i]];
            if (d[cur.to] != d[v] + 1) continue;
            int pushed = dfs(cur.to, min(flow, cur.cap - cur.flow));
            if (pushed > 0) {
                edges[e[v][i]].flow += pushed;
                edges[e[v][i] ^ 1].flow -= pushed;
                return pushed;
            }
        }
        return 0;
    }

    ll flow() {
        ll flow = 0;
        while (bfs()) {
            while (int pushed = dfs(0, INF)) {
                flow += pushed;
            }
        }
        return flow;
    }
};

void print(vector<pair<int, int>> a) {
    if (a.empty()) printf("%d\n", -1);
    else for (auto o : a) printf("%d %d\n", o.first + 1, o.second + 1);
}

vector<pair<int, int>> solve(vector<vector<int>> a) {
    int n = a.size() + 1;

    Graph gr(1 + n-1 + n + 1);
    for (int i = 0; i < n-1; i++) {
        gr.addEdge(0, 1 + i, 1);
    }
    for (int i = 0; i < n-1; i++) {
        for (int x : a[i]) {
            gr.addEdge(1 + i, 1 + n-1 + x, 1);
        }
    }
    for (int i = 0; i < n; i++) {
        gr.addEdge(1 + n-1 + i, 1 + n-1 + n, 1);
    }
    int fl = gr.flow();

    if (fl != n-1) {
        return vector<pair<int, int>>();
    }

    vector<pair<int, int>> e1, e2;
    for (int i = 0; i < n-1; i++) {
        for (auto id : gr.e[1 + i]) {
            auto ed = gr.edges[id];
            if (ed.to >= 1 + n-1 && ed.to < 1 + n-1 + n) {
                if (ed.flow > 0) {
                    e1.push_back({i, ed.to - (1 + n-1)});
                } else {
                    e2.push_back({i, ed.to - (1 + n-1)});
                }
            }
        }
    }
    assert(e1.size() == n-1);

    vector<int> cov(n);
    for (auto o : e1) cov[o.second] = 1;

    vector<int> ncov;
    for (int i = 0; i < n; i++) if (cov[i] == 0) ncov.push_back(i);
    assert(ncov.size() == 1);

    vector<vector<int>> g(n + n-1);
    for (auto ed : e1) {
        g[ed.first].push_back(n-1 + ed.second);
    }
    for (auto ed : e2) {
        g[n-1 + ed.second].push_back(ed.first);
    }

    vector<char> vis(n-1 + n);

    function<void(int)> dfs = [&](int v) {
        //cerr << v << endl;
        vis[v] = 1;
        for (int to : g[v]) {
            if (!vis[to]) {
                if (v >= n-1) {
                    e1.push_back({to, v - (n-1)});
                }
                dfs(to);
            }
        }
    };
    dfs(n-1 + ncov[0]);

    if ((int)e1.size() != 2 * (n - 1)) {
        return vector<pair<int, int>>();
    }
    sort(e1.begin(), e1.end());

    vector<pair<int, int>> ans;
    for (int i = 0; i < (int)e1.size(); i += 2) {
        assert(e1[i].first == e1[i + 1].first);
        ans.push_back({e1[i].second, e1[i + 1].second});
    }

    {
        vector<int> p(n);
        iota(p.begin(), p.end(), 0);
        function<int(int)> get = [&](int x) {
            if (x == p[x]) return x;
            return p[x] =get(p[x]);
        };
        auto uni = [&](int u, int v) {
            u = get(u);
            v = get(v);
            if (u == v) return 0;
            p[v] = u;
            return  1;
        };
        assert((int)ans.size() == n - 1);
        for (int i = 0; i < n-1; i++) {
            assert(find(a[i].begin(), a[i].end(), ans[i].first) != a[i].end());
            assert(find(a[i].begin(), a[i].end(), ans[i].second) != a[i].end());
            assert(uni(ans[i].first, ans[i].second));
        }
    }

    return ans;
}

int main() {
#ifdef HOME
    assert(freopen("in", "r", stdin));
#endif

    int n;
    while (scanf("%d", &n) == 1) {
        vector<vector<int>> a(n - 1);
        for (int i = 0; i < n - 1; i++) {
            int k;
            scanf("%d", &k);
            a[i].resize(k);
            for (int j = 0; j < k; j++) {
                scanf("%d", &a[i][j]);
                a[i][j]--;
            }
        }

        print(solve(a));
    }

#ifdef HOME
    cerr << "time: " << clock() * 1.0 / CLOCKS_PER_SEC << endl;
#endif
}


Measured memory_bytes: 62504