Problem:
Score : 2200 points

Problem Statement

You are given N-1 subsets of \{1,2,...,N\}. Let the i-th set be E_i.

Let us choose two distinct elements u_i and v_i from each set E_i, and consider a graph T with N vertices and N-1 edges, whose vertex set is \{1,2,..,N\} and whose edge set is (u_1,v_1),(u_2,v_2),...,(u_{N-1},v_{N-1}).
Determine if T can be a tree by properly deciding u_i and v_i.
If it can, additionally find one instance of (u_1,v_1),(u_2,v_2),...,(u_{N-1},v_{N-1}) such that T is actually a tree.

Constraints

2 \leq N \leq 10^5

E_i is a subset of \{1,2,..,N\}.

|E_i| \geq 2

The sum of |E_i| is at most 2 \times 10^5.

Input

Input is given from Standard Input in the following format:

N
c_1 w_{1,1} w_{1,2} ... w_{1,c_1}
:
c_{N-1} w_{N-1,1} w_{N-1,2} ... w_{N-1,c_{N-1}}

Here, c_i stands for the number of elements in E_i, and w_{i,1},...,w_{i,c_i} are the c_i elements in c_i.
Here, 2 \leq c_i \leq N, 1 \leq w_{i,j} \leq N, and w_{i,j} \neq w_{i,k} (1 \leq j < k \leq c_i) hold.

Output

If T cannot be a tree, print -1; otherwise, print the choices of (u_i,v_i) that satisfy the condition, in the following format:

u_1 v_1
:
u_{N-1} v_{N-1}

Sample Input 1

5
2 1 2
3 1 2 3
3 3 4 5
2 4 5

Sample Output 1

1 2
1 3
3 4
4 5

Sample Input 2

6
3 1 2 3
3 2 3 4
3 1 3 4
3 1 2 4
3 4 5 6

Sample Output 2

-1

Sample Input 3

10
5 1 2 3 4 5
5 2 3 4 5 6
5 3 4 5 6 7
5 4 5 6 7 8
5 5 6 7 8 9
5 6 7 8 9 10
5 7 8 9 10 1
5 8 9 10 1 2
5 9 10 1 2 3

Sample Output 3

1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10

Solution in C++ (GCC 9.2.1) (judge verdict: Accepted)

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
using db = double;
using vi = vector<int>;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#ifndef ONLINE_JUDGE
#define debug(x) cout << #x <<'	' << x <<endl
#else
#define debug(x)
#endif
const int inf = 0x3f3f3f3f;
const db eps = 1e-8;
const int mod = 1e9+7;
ll qpow(ll a, ll b){
    ll ret = 1;
    while(b){
        if(b&1)ret = ret*a%mod;
        a = a*a%mod;
        b>>=1;
    }
    return ret;
}
const int maxn = 2e5 + 7;
const int INF = 0x3f3f3f3f;
/*
struct Edge
{
    int from, to, cap, flow;
};
struct Dinic
{
    int n, m, s, t;
    vector<Edge> edges;
    vector<int> G[maxn];
    bool vis[maxn];
    int d[maxn];
    int cur[maxn];

    void AddEdge(int from, int to, int cap, int c = 0)
    {
        edges.push_back(Edge{from, to, cap, 0});
        edges.push_back(Edge{to, from, c, 0});
        m = edges.size();
        G[from].push_back(m - 2);
        G[to].push_back(m - 1);
    }

    bool BFS()
    {
        memset(vis, 0, sizeof(vis));
        queue<int> q;
        q.push(s);
        d[s] = 0;
        vis[s] = 1;
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            for (int i = 0; i < G[u].size(); i++)
            {
                Edge &e = edges[G[u][i]];
                if (!vis[e.to] && e.cap > e.flow)
                {
                    vis[e.to] = 1;
                    d[e.to] = d[u] + 1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];
    }
    int DFS(int u, int dist)
    {
        if (u == t || dist == 0)
            return dist;
        int flow = 0, f;
        for (int &i = cur[u]; i < G[u].size(); i++)
        {
            Edge &e = edges[G[u][i]];
            if (d[u] + 1 == d[e.to] && (f = DFS(e.to, min(dist, e.cap - e.flow))) > 0)
            {
                e.flow += f;
                edges[G[u][i] ^ 1].flow -= f;
                flow += f;
                dist -= f;
                if (!dist)
                    break;
            }
        }
        return flow;
    }
    int Maxflow(int s, int t)
    {
        this->s = s;
        this->t = t;
        int flow = 0;
        while (BFS())
        {
            memset(cur, 0, sizeof(cur));
            flow += DFS(s, INF);
        }
        debug(flow);
        return flow;
    }
    void print(){
    	for(auto u:edges){
    		if(u.flow==0&&u.from>n)
    		cout << u.from << " "<< u.to <<" " << u.flow <<"\n";
		}
	}
}net;*/
#define maxn 250000
#define INF 0x3f3f3f3f

struct Edge {
  int from, to, cap, flow;
  Edge(int u, int v, int c, int f) : from(u), to(v), cap(c), flow(f) {}
};

struct Dinic {
  int n, m, s, t;
  vector<Edge> edges;
  vector<int> G[maxn];
  int d[maxn], cur[maxn];
  bool vis[maxn];

  void init(int n) {
    for (int i = 0; i < n; i++) G[i].clear();
    edges.clear();
  }

  void AddEdge(int from, int to, int cap) {
    edges.push_back(Edge(from, to, cap, 0));
    edges.push_back(Edge(to, from, 0, 0));
    m = edges.size();
    G[from].push_back(m - 2);
    G[to].push_back(m - 1);
  }

  bool BFS() {
    memset(vis, 0, sizeof(vis));
    queue<int> Q;
    Q.push(s);
    d[s] = 0;
    vis[s] = 1;
    while (!Q.empty()) {
      int x = Q.front();
      Q.pop();
      for (int i = 0; i < G[x].size(); i++) {
        Edge& e = edges[G[x][i]];
        if (!vis[e.to] && e.cap > e.flow) {
          vis[e.to] = 1;
          d[e.to] = d[x] + 1;
          Q.push(e.to);
        }
      }
    }
    return vis[t];
  }

  int DFS(int x, int a) {
    if (x == t || a == 0) return a;
    int flow = 0, f;
    for (int& i = cur[x]; i < G[x].size(); i++) {
      Edge& e = edges[G[x][i]];
      if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0) {
        e.flow += f;
        edges[G[x][i] ^ 1].flow -= f;
        flow += f;
        a -= f;
        if (a == 0) break;
      }
    }
    return flow;
  }

  int Maxflow(int s, int t) {
    this->s = s;
    this->t = t;
    int flow = 0;
    while (BFS()) {
      memset(cur, 0, sizeof(cur));
      flow += DFS(s, INF);
    }
    return flow;
  }
}net;
int n;
bool vis1[maxn], vis2[maxn];
int id[maxn], nxt[maxn];
queue<int>q;
vector<int>G[maxn];
bool solve(int n){
	for(int i=1; i<n; ++i){
	//	cout <<"begin :" <<i <<endl;
		for(auto v: net.G[n+i]){	
			if(net.edges[v].to && net.edges[v].flow>0){
				int u = net.edges[v].to;
				id[i] = u;
				vis1[u] = 1;
				
				debug(u);//break;
			}	
		} 
	//	cout <<"end: "<<i <<endl;
	}
	for(int i=1; i<=n; ++i)if(!vis1[i])q.push(i);//, vis2[i]=1;
	int cnt =0;
	debug(q.size());
	while(!q.empty()){
		int x = q.front(); q.pop();
		cnt++;
		for(auto v:G[x]){
			if(!vis2[v]){
				vis2[v] = 1;
				nxt[v] = x;
				q.push(id[v]);
			} 
		}
	}debug(cnt);
	return cnt==n;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin >> n;
	net.n = n;
	net.s = 0, net.t = 2*n;
	for(int i=1; i<n; ++i){
		int x;cin >> x;
		net.AddEdge(0, n+i, 1);
		for(int j=0, u; j<x; ++j){
			cin >> u;
			net.AddEdge(n+i, u, 1);
			G[u].pb(i);
		}
	}
	for(int i=1; i<=n; ++i){
		net.AddEdge(i, 2*n, 1);
	}
	if(net.Maxflow(net.s, net.t)<n-1){
		cout <<"-1\n";return 0;
	}
//	net.print();
	if(!solve(n)){
		cout <<"-1\n";
		return 0;
	}
	for(int i=1; i<n; ++i)cout << id[i] <<" "<< nxt[i] <<"\n";
	
}