#include<queue>
#include<stdio.h>
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
#include<string.h>
using namespace std;

typedef long long LL;
typedef vector<int> VI;

#define REP(i,n) for(int i=0, i##_len=(n); i<i##_len; ++i)
#define EACH(i,c) for(__typeof((c).begin()) i=(c).begin(),i##_end=(c).end();i!=i##_end;++i)
#define eprintf(...) fprintf(stderr, __VA_ARGS__)

template<class T> inline void amin(T &x, const T &y) { if (y<x) x=y; }
template<class T> inline void amax(T &x, const T &y) { if (x<y) x=y; }
template<class Iter> void rprintf(const char *fmt, Iter begin, Iter end) {
    for (bool sp=0; begin!=end; ++begin) { if (sp) putchar(' '); else sp = true; printf(fmt, *begin); }
    putchar('\n');
}

struct Dinic {
    typedef int Flow;
    static const Flow INF = 1<<29;
    struct Edge {
	int src, dst;
	Flow cap;
	int rev;
    };
    typedef vector<vector<Edge> > Graph;
    Graph G;
    vector<int>len, iter;
    Dinic(int N) : G(N) {}
    void add_edge(int u, int v, Flow c) {
	G[u].push_back((Edge){ u, v, c, (int)G[v].size() });
	G[v].push_back((Edge){ v, u, 0, (int)G[u].size()-1 });
    }
    Flow dfs(int v, int s, Flow c) {
	if (v == s || c == 0) return c;
	Flow ret = 0;
	for (int &i=iter[v]; i<(int)G[v].size(); i++) {
	    Edge &e = G[v][i], &re = G[e.dst][e.rev];
	    if (re.cap > 0 && len[v] > len[e.dst]) {
		Flow f = dfs(e.dst, s, min(c-ret, re.cap));
		ret += f;
		e.cap += f; re.cap -= f;
		if (ret == c) break;
	    }
	}
	return ret;
    }
    void bfs(int s) {
	len.assign(G.size(), -1);
	queue<int>qu;
	qu.push(s);
	len[s] = 0;
	for (;!qu.empty();) {
	    int v = qu.front(); qu.pop();
	    for (int i=0; i<(int)G[v].size(); i++) {
		const Edge &e = G[v][i];
		if (e.cap > 0 && len[e.dst] == -1) {
		    len[e.dst] = len[v] + 1;
		    qu.push(e.dst);
		}
	    }
	}
    }
    Flow _flow;
    Flow flow(int source, int sink, Flow limit=-1) {
	if (limit == -1) limit = INF;
	Flow ret = 0;
	while (true) {
	    bfs(source);
	    if (len[sink] == -1 || limit == 0) return _flow = ret;
	    iter.assign(G.size(), 0);
	    Flow tmp = dfs(sink, source, limit);
	    ret += tmp;
	    limit -= tmp;
	}
    }
};

const Dinic::Flow Dinic::INF;
int N;
VI E[100011];
VI R[100011];
VI G[100011];
bool use[100011];
pair<int, int> ans[100011];

void MAIN() {
    scanf("%d", &N);
    REP (i, N-1) {
	int K;
	scanf("%d", &K);
	E[i].resize(K);
	REP (j, K) scanf("%d", &E[i][j]), E[i][j]--;
    }

    int RIGHT = N-1;
    int SRC = RIGHT+N-1, SNK = SRC+1;
    Dinic D(SNK+1);

    REP (i, N-1) {
	G[i] = E[i];
	G[i].erase(remove(G[i].begin(), G[i].end(), N-1), G[i].end());
	EACH (e, E[i]) {
	    R[*e].push_back(i);

	    if (*e < N-1) D.add_edge(i, *e + RIGHT, 1);
	}

	D.add_edge(SRC, i, 1);
	D.add_edge(i+RIGHT, SNK, 1);
    }

    if (D.flow(SRC, SNK) == N-1) {
	VI ord; ord.reserve(N);
	ord.push_back(N-1);
	use[N-1] = true;
	for (int i=0; i<(int)ord.size(); i++) {
	    int v = ord[i];
	    EACH (e, R[v]) if (!use[*e]) {
		int w;
		EACH (f, D.G[*e]) if (f->dst != SRC && f->cap == 0) {
		    w = f->dst - RIGHT;
		}
		ans[*e] = make_pair(v, w);
		ord.push_back(w);
		use[*e] = true;
	    }
	}

	if ((int)ord.size() == N) {
	    REP (i, N-1) printf("%d %d\n", ans[i].first+1, ans[i].second+1);
	    return;
	}
    }
    puts("-1");
}

int main() {
    int TC = 1;
//    scanf("%d", &TC);
    REP (tc, TC) MAIN();
    return 0;
}



Measured memory_bytes: 47968