//fuck my life I'm such a miserable retard
//fuck my life it's past midnight
//fuck my life I don't usually stay up this late
//fuck my life it's all just because I can't solve this problem
//fuck my life I don't think it's that hard
//fuck my life I'm just being stupid
//fuck my life I hope I get AC with this shit
//fuck my life I cant prove it
#include<bits/stdc++.h>
#define all(x) x.begin(), x.end()
using namespace std;
using ll = long long;
const int maxn = 10100, mod = 1e9 + 7, inf = 1<<30;
template<typename T, int dir>
struct dinic {
	struct edge {
		int from, to;
		T r, c;
		edge(int from, int to, T c) : from(from), to(to), r(0), c(c) {}
	};
	vector<edge> e;
	vector<vector<int>> g;
	vector<int> h, pos;
	int n, s, t;
	dinic(int n, int s, int t) : n(n), s(s), t(t) {
		g.resize(n);
	}
	void add_edge(int u, int v, T c) {
		g[u].push_back(e.size());
		e.push_back(edge(u, v, c));
		swap(u, v);
		g[u].push_back(e.size());
		e.push_back(edge(u, v, dir?0:c));
	}
	bool bfs() {
		h.assign(n, -1);
		h[t] = 0;
		queue<int> q;
		for(q.push(t); !q.empty(); q.pop()) {
			int u = q.front();
			for(auto i : g[u]) if(int v = e[i].to; h[v] == -1 && e[i^1].c - e[i^1].r > 0) {
				h[v] = h[u] + 1;
				q.push(v);
			}
		}
		return h[s] != -1;
	}
	T dfs(int v, T cap = inf) {
		if(v == t) return cap;
		for(int &xi = pos[v]; xi < g[v].size(); xi++) {
			int x = g[v][xi];
			int i = e[x].to;
			if(h[v]-h[i] != 1 || e[x].c-e[x].r <= 0) continue;
			T f = dfs(i, min(cap, e[x].c-e[x].r));
			if(!f) continue;
			e[x].r += f;
			e[x^1].r -= f;
			return f;
		}
		return 0;
	}
	T findflow() {
		T flow = 0, c;
		while(bfs()) {
			pos.assign(n, 0);
			while(c = dfs(s)) flow += c;
		}
		return flow;
	}
	vector<array<int, 2>> getmatching() {
		vector<array<int, 2>> matching;
		for(auto i : e) {
			if(i.from == s || i.to == t || i.r != 1) continue;
			matching.push_back({i.from, i.to});
		}
		return matching;
	}
};
struct dsu {
	vector<int> r, p;
	dsu(int n) : r(n, 1), p(n) { iota(all(p), 0); }
	void unite(int i, int j) {
		i = par(i), j = par(j);
		if(i == j) return;
		if(r[i] < r[j]) swap(i, j);
		p[j] = i;
		r[i] += r[j];
	}
	int con(int i, int j) {
		return par(i) == par(j);
	}
	int par(int i) {
		return i != p[i] ? p[i] = par(p[i]) : i;
	}
};
int n;
vector<int> vis, deg, match, lmatch;
vector<array<int, 2>> res;
vector<int> adj[1<<17];
dsu tmp(0);
void process(int v) {
	vis[v] = 1;
	for(auto u : adj[v]) if(match[u] != -1 && !vis[match[u]]) {
		tmp.unite(match[u], v);
		res[u] = {match[u], v};
		process(match[u]);
	}
}
int main() {
	cin.tie(0)->sync_with_stdio(0);
	cin >> n;
	vector<vector<int>> f(n-1);
	int s = n+1;
	tmp = (n);
	deg = vector<int>(n);
	match.resize(n, -1);
	lmatch.resize(n, -1);
	vis.resize(n);
	int kk = 0;
	for(auto &i : f) {
		int t;cin >> t;
		s += t;
		i.resize(t);
		for(auto &j : i) cin >> j, assert(j-1 < n), deg[j-1]++, adj[j-1].push_back(kk);
		kk++;
	}
	dinic<int, 1> d(s, 0, s-1);
	mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
	for(int i = 1; i < n; i++) {
		d.add_edge(0, i, 1);
		for(auto j : f[i-1]) {
			d.add_edge(i, n - 1 + j, 1);
		}
	}
	for(int i = n; i < 2*n; i++) d.add_edge(i, s - 1, 1);
	if(d.findflow() != n-1) return cout << -1, 0;
	vector<array<int, 2>> matching = d.getmatching();
	res.resize(n-1);
	set<int> q;
	for(int i = 0; i < n; i++) q.insert(i);
	for(auto [i, x] : matching) {
		match[i-1] = x-n;
		lmatch[x-n] = i-1;
		q.erase(match[i-1]);
	}
	process(*q.begin());
	if(tmp.r[tmp.par(0)] != n) return cout << -1, 0;
	for(auto [a, b] : res) cout << a+1 << " " << b+1 << '\n';
	return 0;
}


Measured memory_bytes: 63720