#include <cstdio>

using namespace std;
const int Max_N(1050);
typedef unsigned long long int ULL;

namespace io
{
	const int SIZE = (1 << 21) + 1;
	char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
	#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
	inline void flush (){fwrite (obuf, 1, oS - obuf, stdout);oS = obuf;}
	inline void putc (char x){*oS ++ = x;if (oS == oT) flush ();}
	template <class I>
	inline void gi (I &x) {for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
		for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;}
	template <class I>
	inline void print (I x){
		if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;while(x) qu[++ qr] = x % 10 + '0',  x /= 10;while (qr) putc (qu[qr--]);}
	struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io::gi;
using io::putc;
using io::print;

int N, Cnt[1 << 16];

inline ULL cut(ULL S)
{
	return S & ((1ULL << 16ULL) - 1ULL);
}

inline int popcount(const ULL &S)
{
	return Cnt[cut(S)] + Cnt[cut(S >> 16ULL)] + Cnt[cut(S >> 32ULL)] + Cnt[cut(S >> 48ULL)];
}

struct Bitset
{
	ULL B[(Max_N >> 6) + 5];
	inline void set(int pos)
	{
		B[pos >> 6] |= (1ULL << (static_cast<ULL>(pos) & 63ULL));
	}
	bool qry(int pos) const
	{
		return B[pos >> 6] & (1ULL << (static_cast<ULL>(pos) & 63ULL));
	}
	inline int popcount() const
	{
		int Ret(0);
		for (int i = 0;i <= (N >> 6);++i)
			Ret += ::popcount(B[i]);
		return Ret;
	}
	Bitset& operator&=(const Bitset &b)
	{
		for (int i = 0;i <= (N >> 6);++i)
			B[i] &= b.B[i];
		return *this;
	}
	inline bool operator!=(const Bitset &b) const
	{
		for (int i = 0;i <= (N >> 6);++i)
			if (B[i] != b.B[i])
				return true;
		return false;
	}
};
Bitset Near[Max_N], Dis1[Max_N];

bool notleaf_1()
{
	for (int i = 1;i <= N;++i)
		if (Near[i].popcount() < N)
			return false;
	for (int i = 2;i <= N;++i)
		print(1), putc(' '), print(i), putc('\n');
	return true;
}

bool notleaf_2()
{
	int Cnt = 0;
	for (int i = 1;i <= N;++i)
		if (Near[i].popcount() == N)
			++Cnt;
	if (Cnt != 2)
		return false;
	Bitset Find = Near[1];
	int A = 0, B = 0, goA = 0, goB = 0;
	for (int i = 1;i <= N;++i)
	{
		Find &= Near[i];
		if (Near[i].popcount() < N)
			if (goA == 0)
				goA = i;
			else
				if (Near[i] != Near[goA])
					if (goB == 0)
						goB = i;
					else
						if (Near[i] != Near[goB])
							return false;
	}
	if (goA == 0 || goB == 0 || Find.popcount() != 2)
		return false;
	for (int u = 1;u <= N;++u)
		if (Find.qry(u))
			if (A == 0)
				A = u;
			else
				B = u;
	print(A), putc(' '), print(B), putc('\n');
	for (int i = 1;i <= N;++i)
		if (i != A && i != B && Near[goA].qry(i))
			print(A), putc(' '), print(i), putc('\n');
	for (int i = 1;i <= N;++i)
		if (i != A && i != B && Near[goB].qry(i))
			print(B), putc(' '), print(i), putc('\n');
	return true;
}

bool G[Max_N][Max_N], Leaf[Max_N];

int main()
{
	freopen("566E.in", "r", stdin);
	for (int S = 0;S < (1 << 16);++S)
		for (int i = 0;i < 16;++i)
			Cnt[S] += ((S & (1 << i)) != 0);
	gi(N);
	for (int i = 1, k;i <= N;++i)
	{
		Leaf[i] = true;
		gi(k);
		for (int u;k--;)
			gi(u), Near[i].set(u);
	}
	if (notleaf_1())
		return 0;
	if (notleaf_2())
		return 0;
	Bitset temp;
	for (int i = 1;i <= N;++i)
		for (int j = i + 1;j <= N;++j)
			if (((temp = Near[i]) &= Near[j]).popcount() == 2)
			{
				int p, q;
				p = q = 0;
				for (int x = 0, u;x <= (N >> 6);++x)
					if (temp.B[x])
						for (ULL b = 0ULL;b <= 63ULL;++b)
							if (temp.B[x] & (1ULL << b))
							{
								u = (x << 6) + b;
								if (p == 0)
									p = u;
								else
									q = u;
							}
				if (G[p][q])
					continue;
				G[p][q] = G[q][p] = true, Dis1[p].set(q), Dis1[q].set(p);
				print(p), putc(' '), print(q), putc('\n'), Leaf[p] = Leaf[q] = false;
			}
	for (int i = 1;i <= N;++i)
		if (Leaf[i])
			for (int j = 1;j <= N;++j)
				if (Near[j].qry(i))
					Dis1[j].set(i);
	for (int i = 1;i <= N;++i)
		if (Leaf[i])
			for (int j = 1;j <= N;++j)
				if (!Leaf[j] && !(Dis1[j] != Near[i]))
				{
					print(i), putc(' '), print(j), putc('\n');
					break;
				}
	return 0;
}


#include <cstdio>

using namespace std;
const int Max_N(1050);
typedef unsigned long long int ULL;

namespace io
{
	const int SIZE = (1 << 21) + 1;
	char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
	#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
	inline void flush (){fwrite (obuf, 1, oS - obuf, stdout);oS = obuf;}
	inline void putc (char x){*oS ++ = x;if (oS == oT) flush ();}
	template <class I>
	inline void gi (I &x) {for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
		for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;}
	template <class I>
	inline void print (I x){
		if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;while(x) qu[++ qr] = x % 10 + '0',  x /= 10;while (qr) putc (qu[qr--]);}
	struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io::gi;
using io::putc;
using io::print;

int N, Cnt[1 << 16];

inline ULL cut(ULL S)
{
	return S & ((1ULL << 16ULL) - 1ULL);
}

inline int popcount(const ULL &S)
{
	return Cnt[cut(S)] + Cnt[cut(S >> 16ULL)] + Cnt[cut(S >> 32ULL)] + Cnt[cut(S >> 48ULL)];
}

struct Bitset
{
	ULL B[Max_N / 64 + 5];
	inline void set(int pos)
	{
		B[pos >> 6] |= (1ULL << (static_cast<ULL>(pos) & 63ULL));
	}
	bool qry(int pos) const
	{
		return B[pos >> 6] & (1ULL << (static_cast<ULL>(pos) & 63ULL));
	}
	inline int popcount() const
	{
		int Ret(0);
		for (int i = 0;i <= (N >> 6);++i)
			Ret += ::popcount(B[i]);
		return Ret;
	}
	Bitset& operator&=(const Bitset &b)
	{
		for (int i = 0;i <= (N >> 6);++i)
			B[i] &= b.B[i];
		return *this;
	}
	inline bool operator!=(const Bitset &b) const
	{
		for (int i = 0;i <= (N >> 6);++i)
			if (B[i] != b.B[i])
				return true;
		return false;
	}
};
Bitset Near[Max_N], Dis1[Max_N];

bool notleaf_1()
{
	for (int i = 1;i <= N;++i)
		if (Near[i].popcount() < N)
			return false;
	for (int i = 2;i <= N;++i)
		print(1), putc(' '), print(i), putc('\n');
	return true;
}

bool notleaf_2()
{
	int Cnt = 0;
	for (int i = 1;i <= N;++i)
		if (Near[i].popcount() == N)
			++Cnt;
	if (Cnt != 2)
		return false;
	Bitset Find = Near[1];
	int A = 0, B = 0, goA = 0, goB = 0;
	for (int i = 1;i <= N;++i)
	{
		Find &= Near[i];
		if (Near[i].popcount() < N)
			if (goA == 0)
				goA = i;
			else
				if (Near[i] != Near[goA])
					if (goB == 0)
						goB = i;
					else
						if (Near[i] != Near[goB])
							return false;
	}
	if (Find.popcount() != 2)
		return false;
	for (int x = 0, u;x <= (N >> 6);++x)
		if (Find.B[x])
			for (ULL b = 0ULL;b <= 63ULL;++b)
				if (Find.B[x] & (1ULL << b))
				{
					u = (x << 6) + b;
					if (A == 0)
						A = u;
					else
						B = u;
				}
	print(A), putc(' '), print(B), putc('\n');
	for (int i = 1;i <= N;++i)
		if (i != A && i != B && Near[goA].qry(i))
			print(A), putc(' '), print(i), putc('\n');
	for (int i = 1;i <= N;++i)
		if (i != A && i != B && Near[goB].qry(i))
			print(B), putc(' '), print(i), putc('\n');
	return true;
}

bool G[Max_N][Max_N], Leaf[Max_N];

int main()
{
	for (int S = 0;S < (1 << 16);++S)
		for (int i = 0;i < 16;++i)
			Cnt[S] += ((S & (1 << i)) != 0);
	gi(N);
	for (int i = 1, k;i <= N;++i)
	{
		Leaf[i] = true;
		gi(k);
		for (int u;k--;)
			gi(u), Near[i].set(u);
	}
	if (notleaf_1())
		return 0;
	if (notleaf_2())
		return 0;
	Bitset temp;
	for (int i = 1;i <= N;++i)
		for (int j = i + 1;j <= N;++j)
			if (((temp = Near[i]) &= Near[j]).popcount() == 2)
			{
				int p, q;
				p = q = 0;
				for (int x = 0, u;x <= (N >> 6);++x)
					if (temp.B[x])
						for (ULL b = 0ULL;b <= 63ULL;++b)
							if (temp.B[x] & (1ULL << b))
							{
								u = (x << 6) + b;
								if (p == 0)
									p = u;
								else
									q = u;
							}
				if (G[p][q])
					continue;
				G[p][q] = G[q][p] = true, Dis1[p].set(q), Dis1[q].set(p);
				print(p), putc(' '), print(q), putc('\n'), Leaf[p] = Leaf[q] = false;
			}
	for (int i = 1;i <= N;++i)
		if (Leaf[i])
			for (int j = 1;j <= N;++j)
				if (Near[j].qry(i))
					Dis1[j].set(i);
	for (int i = 1;i <= N;++i)
		if (Leaf[i])
			for (int j = 1;j <= N;++j)
				if (!Near[j] && !(Dis1[j] != Near[i]))
				{
					print(i), putc(' '), print(j), putc('\n');
					break;
				}
	return 0;
}


#include <cstdio>
#include <algorithm>

using namespace std;
const int Max_N(1050);
typedef unsigned long long int ULL;

namespace io
{
	const int SIZE = (1 << 21) + 1;
	char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
	#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
	inline void flush (){fwrite (obuf, 1, oS - obuf, stdout);oS = obuf;}
	inline void putc (char x){*oS ++ = x;if (oS == oT) flush ();}
	template <class I>
	inline void gi (I &x) {for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
		for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;}
	template <class I>
	inline void print (I x){
		if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;while(x) qu[++ qr] = x % 10 + '0',  x /= 10;while (qr) putc (qu[qr--]);}
	struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io::gi;
using io::putc;
using io::print;

int N, Cnt[1 << 16];

inline ULL cut(ULL S)
{
	return S & ((1ULL << 16ULL) - 1ULL);
}

inline int popcount(const ULL &S)
{
	return Cnt[cut(S)] + Cnt[cut(S >> 16ULL)] + Cnt[cut(S >> 32ULL)] + Cnt[cut(S >> 48ULL)];
}

struct Bitset
{
	ULL B[(Max_N >> 6) + 5];
	inline void set(int pos)
	{
		B[pos >> 6] |= (1ULL << (static_cast<ULL>(pos) & 63ULL));
	}
	inline bool qry(int pos) const
	{
		return B[pos >> 6] & (1ULL << (static_cast<ULL>(pos) & 63ULL));
	}
	inline int popcount() const
	{
		int Ret(0);
		for (int i = 0;i <= (N >> 6);++i)
			Ret += ::popcount(B[i]);
		return Ret;
	}
	inline bool have(const Bitset &b) const
	{
		for (int i = 0;i <= (N >> 6);++i)
			if ((B[i] & b.B[i]) != b.B[i])
				return false;
		return true;
	}
	Bitset& operator&=(const Bitset &b)
	{
		for (int i = 0;i <= (N >> 6);++i)
			B[i] &= b.B[i];
		return *this;
	}
	Bitset operator&(const Bitset &b) const
	{
		Bitset c(*this);
		c &= b;
		return c;
	}
	inline bool operator!=(const Bitset &b) const
	{
		for (int i = 0;i <= (N >> 6);++i)
			if (B[i] != b.B[i])
				return true;
		return false;
	}
};
Bitset Near[Max_N], Dis1[Max_N], notleaf;

inline Bitset operator-(const Bitset &a, const Bitset &b)
{
	Bitset c;
	for (int i = 0;i <= (N >> 6);++i)
		c.B[i] = a.B[i] - b.B[i];
	return c;
}

bool notleaf_1()
{
	for (int i = 1;i <= N;++i)
		if (Near[i].popcount() < N)
			return false;
	for (int i = 2;i <= N;++i)
		print(1), putc(' '), print(i), putc('\n');
	return true;
}

bool notleaf_2()
{
	int Cnt = 0;
	for (int i = 1;i <= N;++i)
		if (Near[i].popcount() == N)
			++Cnt;
	if (Cnt != 2)
		return false;
	Bitset Find = Near[1];
	int A = 0, B = 0, goA = 0, goB = 0;
	for (int i = 1;i <= N;++i)
	{
		Find &= Near[i];
		if (Near[i].popcount() < N)
			if (goA == 0)
				goA = i;
			else
				if (Near[i] != Near[goA])
					if (goB == 0)
						goB = i;
					else
						if (Near[i] != Near[goB])
							return false;
	}
	if (goA == 0 || goB == 0 || Find.popcount() != 2)
		return false;
	for (int u = 1;u <= N;++u)
		if (Find.qry(u))
			if (A == 0)
				A = u;
			else
				B = u;
	print(A), putc(' '), print(B), putc('\n');
	for (int i = 1;i <= N;++i)
		if (i != A && i != B && Near[goA].qry(i))
			print(A), putc(' '), print(i), putc('\n');
	for (int i = 1;i <= N;++i)
		if (i != A && i != B && Near[goB].qry(i))
			print(B), putc(' '), print(i), putc('\n');
	return true;
}

int main()
{
	for (int S = 0;S < (1 << 16);++S)
		for (int i = 0;i < 16;++i)
			Cnt[S] += ((S & (1 << i)) != 0);
	gi(N);
	if (N == 2)
	{
		print(1), putc(' '), print(2), putc('\n');
		return 0;
	}
	for (int i = 1, k;i <= N;++i)
	{
		gi(k);
		for (int u;k--;)
			gi(u), Near[i].set(u);
	}
	if (notleaf_1())
		return 0;
	if (notleaf_2())
		return 0;
	Bitset temp;
	for (int i = 1;i <= N;++i)
		for (int j = i;j <= N;++j)
			if (((temp = Near[i]) &= Near[j]).popcount() == 2)
			{
				int p, q;
				p = q = 0;
				for (int x = 0, u;x <= (N >> 6);++x)
					if (temp.B[x])
						for (ULL b = 0ULL;b <= 63ULL;++b)
							if (temp.B[x] & (1ULL << b))
							{
								u = (x << 6) + b;
								if (p == 0)
									p = u;
								else
									q = u;
							}
				if (Dis1[p].qry(q))
					continue;
				Dis1[p].set(q), Dis1[q].set(p), print(p), putc(' '), print(q), putc('\n'), notleaf.set(p), notleaf.set(q), Dis1[p].set(p), Dis1[q].set(q);
			}
	for (int i = 1;i <= N;++i)
		if (!notleaf.qry(i))
		{
			int Min = 0X3F3F3F3F;
			Bitset temp;
			for (int j = 1;j <= N;++j)
				if (Near[j].qry(i))
					Min = min(Min, (Near[j] & notleaf).popcount());
			for (int j = 1;j <= N;++j)
				if (Near[j].qry(i) && (Near[j] & notleaf).popcount() == Min)
					temp = (Near[j] & notleaf);
			for (int j = 1;j <= N;++j)
				if (temp.qry(j) && !(Dis1[j] != temp))
				{
					print(i), putc(' '), print(j), putc('\n');
					break;
				}
		}
	return 0;
}


#include <bits/stdc++.h>

const int N = 1054;
typedef std::bitset <N> bitset;

int n;
bitset leaf, G[N], B[N];

int main() {
	int i, j, k, u, v, L; bitset r, best;
	scanf("%d", &n);
	for (i = 0; i < n; ++i)
		for (scanf("%d", &k); k; --k) scanf("%d", &j), B[i].set(j);
	for (i = 1; i <= n; ++i) G[i].set(i), leaf.set(i);
	for (i = 0; i < n; ++i)
		for (j = i + 1; j < n; ++j)
			if ((r = B[i] & B[j]).count() == 2) {
				u = r._Find_first(), v = r._Find_next(u);
				if (!G[u].test(v))
					G[u].set(v), G[v].set(u), leaf.reset(u), leaf.reset(v);
			}
	L = leaf.count();
	if (L == n) {for (i = 2; i <= n; ++i) printf("1 %d\n", i); return 0;}
	if (L == n - 2) {
		for (i = 0; i < n && B[i].count() == n; ++i); r = B[i];
		for (i = leaf._Find_first(); i != N; i = leaf._Find_next(i))
			j = r.test(i) ? u : v, G[i].set(j), G[j].set(i);
	} else
		for (i = leaf._Find_first(); i != N; i = leaf._Find_next(i)) {
			for (k = INT_MAX, j = 0; j < n; ++j)
				if (B[j].test(i))
					if (r = B[j] & ~leaf, (v = r.count()) < k)
						best = r, k = v;
			for (j = best._Find_first(); j != N; j = best._Find_next(j))
				if ((G[j] & ~leaf) == best) {G[i].set(j), G[j].set(i); break;}
		}
	for (i = 1; i <= n; ++i)
		for (j = G[i]._Find_next(i); j != N; j = G[i]._Find_next(j))
			printf("%d %d\n", i, j);
	return 0;
}


#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
using namespace std;

namespace zyt
{
	template<typename T>
	inline bool read(T &x)
	{
		char c;
		bool f = false;
		x = 0;
		do
			c = getchar();
		while (c != EOF && c != '-' && !isdigit(c));
		if (c == EOF)
			return false;
		if (c == '-')
			f = true, c = getchar();
		do
			x = x * 10 + c - '0', c = getchar();
		while (isdigit(c));
		if (f)
			x = -x;
		return true;
	}
	template<typename T>
	inline void write(T x)
	{
		static char buf[20];
		char *pos = buf;
		if (x < 0)
			putchar('-'), x = -x;
		do
			*pos++ = x % 10 + '0';
		while (x /= 10);
		while (pos > buf)
			putchar(*--pos);
	}
	typedef pair<int, int> pii;
	const int N = 1e3 + 10;
	int n, d[N];
	bool vis[N][N];
	class bitset
	{
	private:
		const static int B = 32, BB = 5;
		unsigned data[N / B + 10];
		int len, n;
		static int ct[1 << (B >> 1)];
		static bool flag;
	public:
		bitset(const int _n = 0)
			: n(_n)
		{
			memset(data, 0, sizeof(data));
			len = (n >> BB) + 1;
			if (!flag)
			{
				flag = true;
				for (int i = 0; i < (1 << (B >> 1)); i++)
					ct[i] = ct[i >> 1] + (i & 1);
			}
		}
		void set(const int p)
		{
			data[p >> BB] |= (1U << (p & (B - 1)));
		}
		void reset(const int p)
		{
			data[p >> BB] &= ~(1U << (p & (B - 1)));
		}
		bool operator [] (const unsigned p) const
		{
			return data[p >> BB] & (1U << (p & (B - 1)));
		}
		bitset operator & (const bitset &b) const
		{
			bitset ans(n);
			for (int i = 0; i < len; i++)
				ans.data[i] = (data[i] & b.data[i]);
			return ans;
		}
		int count() const
		{
			int ans = 0;
			for (int i = 0; i < len; i++)
				ans += ct[data[i] >> (B >> 1)] + ct[data[i] & ((1 << (B >> 1)) - 1)];
			return ans;
		}
		int first() const
		{
			for (int i = 0; i < len; i++)
				if (data[i])
				{
					int ans = (i << BB), tmp = data[i];
					while (!(tmp & 1))
						tmp >>= 1, ++ans;
					return ans;
				}
		}
	}bs[N];
	int bitset::ct[1 << (bitset::B >> 1)];
	bool bitset::flag;
	pii e[N];
	int work()
	{
		read(n);
		for (int i = 1; i <= n; i++)
		{
			int k;
			read(k);
			bs[i] = bitset(n);
			while (k--)
			{
				int a;
				read(a);
				bs[i].set(a);
			}
		}
		int cnt = 0;
		for (int i = 1; i <= n; i++)
			for (int j = i + 1; j <= n; j++)
			{
				bitset tmp = (bs[i] & bs[j]);
				if (tmp.count() == 2)
				{
					int a = tmp.first();
					tmp.reset(a);
					int b = tmp.first();
					if (!vis[a][b])
					{
						printf("%d %d\n", a, b);
						e[cnt++] = pii(a, b);
						++d[a], ++d[b];
						vis[a][b] = vis[b][a] = true;
					}
				}
			}
		if (!cnt)
		{
			for (int i = 2; i <= n; i++)
				printf("%d %d\n", 1, i);
		}
		else if (cnt == 1)
		{
			for (int i = 1; i <= n; i++)
				if (bs[i].count() < n)
				{
					for (int j = 1; j <= n; j++)
						if (!d[j])
						{
							if (bs[i][j])
								printf("%d %d\n", e[0].first, j);
							else
								printf("%d %d\n", e[0].second, j);
						}
					break;
				}
		}
		else
		{
			for (int i = 1; i <= n; i++)
				if (!d[i])
				{
					static int deg[N];
					bitset b(n);
					bool flag = false;
					memset(deg, 0, sizeof(int[n + 1]));
					for (int j = 1; j <= n; j++)
						if (bs[j][i])
						{
							if (flag)
								b = (b & bs[j]);
							else
								b = bs[j], flag = true;
						}
					for (int j = 0; j < cnt; j++)
						if (b[e[j].first] && b[e[j].second])
							++deg[e[j].first], ++deg[e[j].second];
					for (int j = 1, c = b.count(); j <= n; j++)
						if (b[j])
						{
							if (c == 2)
							{
								if (d[j] == 1)
									printf("%d %d\n", i, j);
							}
							else
							{
								if (deg[j] > 1)
									printf("%d %d\n", i, j);
							}
						}
				}
		}
		return 0;
	}
}
int main()
{
	return zyt::work();
}


#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
using namespace std;

namespace zyt
{
	template<typename T>
	inline bool read(T &x)
	{
		char c;
		bool f = false;
		x = 0;
		do
			c = getchar();
		while (c != EOF && c != '-' && !isdigit(c));
		if (c == EOF)
			return false;
		if (c == '-')
			f = true, c = getchar();
		do
			x = x * 10 + c - '0', c = getchar();
		while (isdigit(c));
		if (f)
			x = -x;
		return true;
	}
	template<typename T>
	inline void write(T x)
	{
		static char buf[20];
		char *pos = buf;
		if (x < 0)
			putchar('-'), x = -x;
		do
			*pos++ = x % 10 + '0';
		while (x /= 10);
		while (pos > buf)
			putchar(*--pos);
	}
	typedef pair<int, int> pii;
	const int N = 1e3 + 10;
	int n, d[N];
	bool vis[N][N];
	class bitset
	{
	private:
		const static int B = 32, BB = 5;
		unsigned data[N / B + 10];
		int len;
		static int ct[1 << (B >> 1)];
		static bool flag;
	public:
		bitset(const int n = 0)
		{
			memset(data, 0, sizeof(data));
			len = n / 32 + 1;
			if (!flag)
			{
				flag = true;
				for (int i = 0; i < (1 << (BB - 1)); i++)
					ct[i] = ct[i >> 1] + (i & 1);
			}
		}
		void set(const int p)
		{
			data[p >> BB] |= (1U << (p & ((1U << BB) - 1)));
		}
		void reset(const int p)
		{
			data[p >> BB] &= ~(1U << (p & ((1U << BB) - 1)));
		}
		bool operator [] (const unsigned p) const
		{
			return data[p >> BB] & (1U << (p & ((1U << BB) - 1)));
		}
		bitset operator & (const bitset &b) const
		{
			bitset ans(len);
			for (int i = 0; i < len; i++)
				ans.data[i] = (data[i] & b.data[i]);
			return ans;
		}
		int count() const
		{
			int ans = 0;
			for (int i = 0; i < len; i++)
				ans += ct[data[i] >> (BB - 1)] + ct[data[i] & ((1 << (BB - 1)) - 1)];
			return ans;
		}
		int first() const
		{
			for (int i = 0; i < len; i++)
				if (data[i])
				{
					int ans = (i << BB), tmp = data[i];
					while (!(tmp & 1))
						tmp >>= 1, ++ans;
					return ans;
				}
		}
	}bs[N];
	int bitset::ct[1 << (bitset::B >> 1)];
	bool bitset::flag;
	pii e[N];
	int work()
	{
		read(n);
		for (int i = 1; i <= n; i++)
		{
			int k;
			read(k);
			while (k--)
			{
				int a;
				read(a);
				bs[i].set(a);
			}
		}
		int cnt = 0;
		for (int i = 1; i <= n; i++)
			for (int j = i + 1; j <= n; j++)
			{
				bitset tmp = (bs[i] & bs[j]);
				if (tmp.count() == 2)
				{
					int a = tmp.first();
					tmp.reset(a);
					int b = tmp.first();
					if (!vis[a][b])
					{
						printf("%d %d\n", a, b);
						e[cnt++] = pii(a, b);
						++d[a], ++d[b];
						vis[a][b] = vis[b][a] = true;
					}
				}
			}
		if (!cnt)
		{
			for (int i = 2; i <= n; i++)
				printf("%d %d\n", 1, i);
		}
		else if (cnt == 1)
		{
			for (int i = 1; i <= n; i++)
				if (bs[i].count() < n)
				{
					for (int j = 1; j <= n; j++)
						if (!d[j])
						{
							if (bs[i][j])
								printf("%d %d\n", e[0].first, j);
							else
								printf("%d %d\n", e[0].second, j);
						}
					break;
				}
		}
		else
		{
			for (int i = 1; i <= n; i++)
				if (!d[i])
				{
					static int deg[N];
					bitset b;
					bool flag = false;
					memset(deg, 0, sizeof(int[n + 1]));
					for (int j = 1; j <= n; j++)
						if (bs[j][i])
						{
							if (flag)
								b = (b & bs[j]);
							else
								b = bs[j], flag = true;
						}
					for (int j = 0; j < cnt; j++)
						if (b[e[j].first] && b[e[j].second])
							++deg[e[j].first], ++deg[e[j].second];
					for (int j = 1, c = b.count(); j <= n; j++)
						if (b[j])
						{
							if (c == 2)
							{
								if (d[j] == 1)
									printf("%d %d\n", i, j);
							}
							else
							{
								if (deg[j] > 1)
									printf("%d %d\n", i, j);
							}
						}
				}
		}
		return 0;
	}
}
int main()
{
	return zyt::work();
}


#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
using namespace std;

namespace zyt
{
	template<typename T>
	inline bool read(T &x)
	{
		char c;
		bool f = false;
		x = 0;
		do
			c = getchar();
		while (c != EOF && c != '-' && !isdigit(c));
		if (c == EOF)
			return false;
		if (c == '-')
			f = true, c = getchar();
		do
			x = x * 10 + c - '0', c = getchar();
		while (isdigit(c));
		if (f)
			x = -x;
		return true;
	}
	template<typename T>
	inline void write(T x)
	{
		static char buf[20];
		char *pos = buf;
		if (x < 0)
			putchar('-'), x = -x;
		do
			*pos++ = x % 10 + '0';
		while (x /= 10);
		while (pos > buf)
			putchar(*--pos);
	}
	typedef pair<int, int> pii;
	const int N = 1e3 + 10;
	int n, d[N];
	bool vis[N][N];
	class bitset
	{
	private:
		const static int B = 32, BB = 5;
		unsigned data[N / B + 10];
		int len, n;
		static int ct[1 << (B >> 1)];
		static bool flag;
	public:
		bitset(const int _n = 0)
			: n(_n)
		{
			memset(data, 0, sizeof(data));
			len = (n >> BB) + 1;
			if (!flag)
			{
				flag = true;
				for (int i = 0; i < (1 << (B >> 1)); i++)
					ct[i] = ct[i >> 1] + (i & 1);
			}
		}
		void set(const int p)
		{
			data[p >> BB] |= (1U << (p & (B - 1)));
		}
		void reset(const int p)
		{
			data[p >> BB] &= ~(1U << (p & (B - 1)));
		}
		bool operator [] (const unsigned p) const
		{
			return data[p >> BB] & (1U << (p & (B - 1)));
		}
		bitset operator & (const bitset &b) const
		{
			bitset ans(n);
			for (int i = 0; i < len; i++)
				ans.data[i] = (data[i] & b.data[i]);
			return ans;
		}
		int count() const
		{
			int ans = 0;
			for (int i = 0; i < len; i++)
				ans += ct[data[i] >> (B >> 1)] + ct[data[i] & ((1 << (B >> 1)) - 1)];
			return ans;
		}
		int first() const
		{
			for (int i = 0; i < len; i++)
				if (data[i])
				{
					int ans = (i << BB), tmp = data[i];
					while (!(tmp & 1))
						tmp >>= 1, ++ans;
					return ans;
				}
		}
	}bs[N];
	int bitset::ct[1 << (bitset::B >> 1)];
	bool bitset::flag;
	pii e[N];
	int work()
	{
		read(n);
		for (int i = 1; i <= n; i++)
		{
			int k;
			read(k);
			bs[i] = bitset(n);
			while (k--)
			{
				int a;
				read(a);
				bs[i].set(a);
			}
		}
		int cnt = 0;
		for (int i = 1; i <= n; i++)
			for (int j = i + 1; j <= n; j++)
			{
				bitset tmp = (bs[i] & bs[j]);
				if (tmp.count() == 2)
				{
					int a = tmp.first();
					tmp.reset(a);
					int b = tmp.first();
					if (!vis[a][b])
					{
						printf("%d %d\n", a, b);
						e[cnt++] = pii(a, b);
						++d[a], ++d[b];
						vis[a][b] = vis[b][a] = true;
					}
				}
			}
		if (!cnt)
		{
			for (int i = 2; i <= n; i++)
				printf("%d %d\n", 1, i);
		}
		else if (cnt == 1)
		{
			for (int i = 1; i <= n; i++)
				if (bs[i].count() < n)
				{
					for (int j = 1; j <= n; j++)
						if (!d[j])
						{
							if (bs[i][j])
								printf("%d %d\n", e[0].first, j);
							else
								printf("%d %d\n", e[0].second, j);
						}
					break;
				}
		}
		else
		{
			for (int i = 1; i <= n; i++)
				if (!d[i])
				{
					static int deg[N];
					bitset b(n);
					bool flag = false;
					memset(deg, 0, sizeof(int[n + 1]));
					for (int j = 1; j <= n; j++)
						if (bs[j][i])
						{
							if (flag)
								b = (b & bs[j]);
							else
								b = bs[j], flag = true;
						}
					for (int j = 0; j < cnt; j++)
						if (b[e[j].first] && b[e[j].second])
							++deg[e[j].first], ++deg[e[j].second];
					int c = 0;
					for (int j = 1; j <= n; j++)
						if (d[j] && b[j])
							++c;
					for (int j = 1; j <= n; j++)
						if (b[j])
						{
							if (c == 2)
							{
								if (d[j] == 1)
									printf("%d %d\n", i, j);
							}
							else
							{
								if (deg[j] > 1)
									printf("%d %d\n", i, j);
							}
						}
				}
		}
		return 0;
	}
}
int main()
{
	return zyt::work();
}


#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
using namespace std;

namespace zyt
{
	template<typename T>
	inline bool read(T &x)
	{
		char c;
		bool f = false;
		x = 0;
		do
			c = getchar();
		while (c != EOF && c != '-' && !isdigit(c));
		if (c == EOF)
			return false;
		if (c == '-')
			f = true, c = getchar();
		do
			x = x * 10 + c - '0', c = getchar();
		while (isdigit(c));
		if (f)
			x = -x;
		return true;
	}
	template<typename T>
	inline void write(T x)
	{
		static char buf[20];
		char *pos = buf;
		if (x < 0)
			putchar('-'), x = -x;
		do
			*pos++ = x % 10 + '0';
		while (x /= 10);
		while (pos > buf)
			putchar(*--pos);
	}
	typedef pair<int, int> pii;
	const int N = 1e3 + 10;
	int n, d[N];
	bool vis[N][N];
	class bitset
	{
	private:
		const static int B = 32, BB = 5;
		unsigned data[N / B + 10];
		int len;
		static int ct[1 << (B >> 1)];
		static bool flag;
	public:
		bitset(const int n = 0)
		{
			memset(data, 0, sizeof(data));
			len = n / 32 + 1;
			if (!flag)
			{
				flag = true;
				for (int i = 0; i < (1 << (B >> 1)); i++)
					ct[i] = ct[i >> 1] + (i & 1);
			}
		}
		void set(const int p)
		{
			data[p >> BB] |= (1U << (p & (B - 1)));
		}
		void reset(const int p)
		{
			data[p >> BB] &= ~(1U << (p & (B - 1)));
		}
		bool operator [] (const unsigned p) const
		{
			return data[p >> BB] & (1U << (p & (B - 1)));
		}
		bitset operator & (const bitset &b) const
		{
			bitset ans(len);
			for (int i = 0; i < len; i++)
				ans.data[i] = (data[i] & b.data[i]);
			return ans;
		}
		int count() const
		{
			int ans = 0;
			for (int i = 0; i < len; i++)
				ans += ct[data[i] >> (B >> 1)] + ct[data[i] & ((1 << (B >> 1)) - 1)];
			return ans;
		}
		int first() const
		{
			for (int i = 0; i < len; i++)
				if (data[i])
				{
					int ans = (i << BB), tmp = data[i];
					while (!(tmp & 1))
						tmp >>= 1, ++ans;
					return ans;
				}
		}
	}bs[N];
	int bitset::ct[1 << (bitset::B >> 1)];
	bool bitset::flag;
	pii e[N];
	int work()
	{
		read(n);
		for (int i = 1; i <= n; i++)
		{
			int k;
			read(k);
			while (k--)
			{
				int a;
				read(a);
				bs[i].set(a);
			}
		}
		int cnt = 0;
		for (int i = 1; i <= n; i++)
			for (int j = i + 1; j <= n; j++)
			{
				bitset tmp = (bs[i] & bs[j]);
				if (tmp.count() == 2)
				{
					int a = tmp.first();
					tmp.reset(a);
					int b = tmp.first();
					if (!vis[a][b])
					{
						printf("%d %d\n", a, b);
						e[cnt++] = pii(a, b);
						++d[a], ++d[b];
						vis[a][b] = vis[b][a] = true;
					}
				}
			}
		if (!cnt)
		{
			for (int i = 2; i <= n; i++)
				printf("%d %d\n", 1, i);
		}
		else if (cnt == 1)
		{
			for (int i = 1; i <= n; i++)
				if (bs[i].count() < n)
				{
					for (int j = 1; j <= n; j++)
						if (!d[j])
						{
							if (bs[i][j])
								printf("%d %d\n", e[0].first, j);
							else
								printf("%d %d\n", e[0].second, j);
						}
					break;
				}
		}
		else
		{
			for (int i = 1; i <= n; i++)
				if (!d[i])
				{
					static int deg[N];
					bitset b;
					bool flag = false;
					memset(deg, 0, sizeof(int[n + 1]));
					for (int j = 1; j <= n; j++)
						if (bs[j][i])
						{
							if (flag)
								b = (b & bs[j]);
							else
								b = bs[j], flag = true;
						}
					for (int j = 0; j < cnt; j++)
						if (b[e[j].first] && b[e[j].second])
							++deg[e[j].first], ++deg[e[j].second];
					for (int j = 1, c = b.count(); j <= n; j++)
						if (b[j])
						{
							if (c == 2)
							{
								if (d[j] == 1)
									printf("%d %d\n", i, j);
							}
							else
							{
								if (deg[j] > 1)
									printf("%d %d\n", i, j);
							}
						}
				}
		}
		return 0;
	}
}
int main()
{
	return zyt::work();
}


#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
using namespace std;

namespace zyt
{
	template<typename T>
	inline bool read(T &x)
	{
		char c;
		bool f = false;
		x = 0;
		do
			c = getchar();
		while (c != EOF && c != '-' && !isdigit(c));
		if (c == EOF)
			return false;
		if (c == '-')
			f = true, c = getchar();
		do
			x = x * 10 + c - '0', c = getchar();
		while (isdigit(c));
		if (f)
			x = -x;
		return true;
	}
	template<typename T>
	inline void write(T x)
	{
		static char buf[20];
		char *pos = buf;
		if (x < 0)
			putchar('-'), x = -x;
		do
			*pos++ = x % 10 + '0';
		while (x /= 10);
		while (pos > buf)
			putchar(*--pos);
	}
	typedef pair<int, int> pii;
	const int N = 1e3 + 10;
	int n, d[N];
	bool vis[N][N];
	class bitset
	{
	private:
		const static int B = 32, BB = 5;
		unsigned data[N / B + 10];
		int len;
		static int ct[1 << (B >> 1)];
		static bool flag;
	public:
		bitset(const int n = 0)
		{
			memset(data, 0, sizeof(data));
			len = n / 32 + 1;
			if (!flag)
			{
				flag = true;
				for (int i = 0; i < (1 << (B >> 1)); i++)
					ct[i] = ct[i >> 1] + (i & 1);
			}
		}
		void set(const int p)
		{
			data[p >> BB] |= (1U << (p & (B - 1)));
		}
		void reset(const int p)
		{
			data[p >> BB] &= ~(1U << (p & (B - 1)));
		}
		bool operator [] (const unsigned p) const
		{
			return data[p >> BB] & (1U << (p & (B - 1)));
		}
		bitset operator & (const bitset &b) const
		{
			bitset ans(len);
			for (int i = 0; i < len; i++)
				ans.data[i] = (data[i] & b.data[i]);
			return ans;
		}
		int count() const
		{
			int ans = 0;
			for (int i = 0; i < len; i++)
				ans += ct[data[i] >> (B >> 1)] + ct[data[i] & ((1 << (B >> 1)) - 1)];
			return ans;
		}
		int first() const
		{
			for (int i = 0; i < len; i++)
				if (data[i])
				{
					int ans = (i << BB), tmp = data[i];
					while (!(tmp & 1))
						tmp >>= 1, ++ans;
					return ans;
				}
		}
	}bs[N];
	int bitset::ct[1 << (bitset::B >> 1)];
	bool bitset::flag;
	pii e[N];
	int work()
	{
		read(n);
		for (int i = 1; i <= n; i++)
		{
			int k;
			read(k);
			bs[i] = bitset(n);
			while (k--)
			{
				int a;
				read(a);
				bs[i].set(a);
			}
		}
		int cnt = 0;
		for (int i = 1; i <= n; i++)
			for (int j = i + 1; j <= n; j++)
			{
				bitset tmp = (bs[i] & bs[j]);
				if (tmp.count() == 2)
				{
					int a = tmp.first();
					tmp.reset(a);
					int b = tmp.first();
					if (!vis[a][b])
					{
						printf("%d %d\n", a, b);
						e[cnt++] = pii(a, b);
						++d[a], ++d[b];
						vis[a][b] = vis[b][a] = true;
					}
				}
			}
		if (!cnt)
		{
			for (int i = 2; i <= n; i++)
				printf("%d %d\n", 1, i);
		}
		else if (cnt == 1)
		{
			for (int i = 1; i <= n; i++)
				if (bs[i].count() < n)
				{
					for (int j = 1; j <= n; j++)
						if (!d[j])
						{
							if (bs[i][j])
								printf("%d %d\n", e[0].first, j);
							else
								printf("%d %d\n", e[0].second, j);
						}
					break;
				}
		}
		else
		{
			for (int i = 1; i <= n; i++)
				if (!d[i])
				{
					static int deg[N];
					bitset b(n);
					bool flag = false;
					memset(deg, 0, sizeof(int[n + 1]));
					for (int j = 1; j <= n; j++)
						if (bs[j][i])
						{
							if (flag)
								b = (b & bs[j]);
							else
								b = bs[j], flag = true;
						}
					for (int j = 0; j < cnt; j++)
						if (b[e[j].first] && b[e[j].second])
							++deg[e[j].first], ++deg[e[j].second];
					for (int j = 1, c = b.count(); j <= n; j++)
						if (b[j])
						{
							if (c == 2)
							{
								if (d[j] == 1)
									printf("%d %d\n", i, j);
							}
							else
							{
								if (deg[j] > 1)
									printf("%d %d\n", i, j);
							}
						}
				}
		}
		return 0;
	}
}
int main()
{
	return zyt::work();
}


#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
using namespace std;

namespace zyt
{
	template<typename T>
	inline bool read(T &x)
	{
		char c;
		bool f = false;
		x = 0;
		do
			c = getchar();
		while (c != EOF && c != '-' && !isdigit(c));
		if (c == EOF)
			return false;
		if (c == '-')
			f = true, c = getchar();
		do
			x = x * 10 + c - '0', c = getchar();
		while (isdigit(c));
		if (f)
			x = -x;
		return true;
	}
	template<typename T>
	inline void write(T x)
	{
		static char buf[20];
		char *pos = buf;
		if (x < 0)
			putchar('-'), x = -x;
		do
			*pos++ = x % 10 + '0';
		while (x /= 10);
		while (pos > buf)
			putchar(*--pos);
	}
	typedef pair<int, int> pii;
	const int N = 1e3 + 10;
	int n, d[N];
	bool vis[N][N];
	class bitset
	{
	private:
		const static int B = 32, BB = 5;
		unsigned data[N / B + 10];
		int len;
		static int ct[1 << (BB - 1)];
		static bool flag;
	public:
		bitset(const int n = 0)
		{
			memset(data, 0, sizeof(data));
			len = n / 32 + 1;
			if (!flag)
			{
				flag = true;
				for (int i = 0; i < (1 << (BB - 1)); i++)
					ct[i] = ct[i >> 1] + (i & 1);
			}
		}
		void set(const int p)
		{
			data[p >> BB] |= (1U << (p & ((1U << BB) - 1)));
		}
		void reset(const int p)
		{
			data[p >> BB] &= ~(1U << (p & ((1U << BB) - 1)));
		}
		bool operator [] (const unsigned p) const
		{
			return data[p >> BB] & (1U << (p & ((1U << BB) - 1)));
		}
		bitset operator & (const bitset &b) const
		{
			bitset ans(len);
			for (int i = 0; i < len; i++)
				ans.data[i] = (data[i] & b.data[i]);
			return ans;
		}
		int count() const
		{
			int ans = 0;
			for (int i = 0; i < len; i++)
				ans += ct[data[i] >> (BB - 1)] + ct[data[i] & ((1 << (BB - 1)) - 1)];
			return ans;
		}
		int first() const
		{
			for (int i = 0; i < len; i++)
				if (data[i])
				{
					int ans = (i << BB), tmp = data[i];
					while (!(tmp & 1))
						tmp >>= 1, ++ans;
					return ans;
				}
		}
	}bs[N];
	int bitset::ct[1 << (bitset::BB - 1)];
	bool bitset::flag;
	pii e[N];
	int work()
	{
		read(n);
		for (int i = 1; i <= n; i++)
		{
			int k;
			read(k);
			while (k--)
			{
				int a;
				read(a);
				bs[i].set(a);
			}
		}
		int cnt = 0;
		for (int i = 1; i <= n; i++)
			for (int j = i + 1; j <= n; j++)
			{
				bitset tmp = (bs[i] & bs[j]);
				if (tmp.count() == 2)
				{
					int a = tmp.first();
					tmp.reset(a);
					int b = tmp.first();
					if (!vis[a][b])
					{
						printf("%d %d\n", a, b);
						e[cnt++] = pii(a, b);
						++d[a], ++d[b];
						vis[a][b] = vis[b][a] = true;
					}
				}
			}
		if (!cnt)
		{
			for (int i = 2; i <= n; i++)
				printf("%d %d\n", 1, i);
		}
		else if (cnt == 1)
		{
			for (int i = 1; i <= n; i++)
				if (bs[i].count() < n)
				{
					for (int j = 1; j <= n; j++)
						if (!d[j])
						{
							if (bs[i][j])
								printf("%d %d\n", e[0].first, j);
							else
								printf("%d %d\n", e[0].second, j);
						}
					break;
				}
		}
		else
		{
			for (int i = 1; i <= n; i++)
				if (!d[i])
				{
					static int deg[N];
					bitset b;
					bool flag = false;
					memset(deg, 0, sizeof(int[n + 1]));
					for (int j = 1; j <= n; j++)
						if (bs[j][i])
						{
							if (flag)
								b = (b & bs[j]);
							else
								b = bs[j], flag = true;
						}
					for (int j = 0; j < cnt; j++)
						if (b[e[j].first] && b[e[j].second])
							++deg[e[j].first], ++deg[e[j].second];
					for (int j = 1, c = b.count(); j <= n; j++)
						if (b[j])
						{
							if (c == 2)
							{
								if (d[j] == 1)
									printf("%d %d\n", i, j);
							}
							else
							{
								if (deg[j] > 1)
									printf("%d %d\n", i, j);
							}
						}
				}
		}
		return 0;
	}
}
int main()
{
	return zyt::work();
}


#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
using namespace std;

namespace zyt
{
	template<typename T>
	inline bool read(T &x)
	{
		char c;
		bool f = false;
		x = 0;
		do
			c = getchar();
		while (c != EOF && c != '-' && !isdigit(c));
		if (c == EOF)
			return false;
		if (c == '-')
			f = true, c = getchar();
		do
			x = x * 10 + c - '0', c = getchar();
		while (isdigit(c));
		if (f)
			x = -x;
		return true;
	}
	template<typename T>
	inline void write(T x)
	{
		static char buf[20];
		char *pos = buf;
		if (x < 0)
			putchar('-'), x = -x;
		do
			*pos++ = x % 10 + '0';
		while (x /= 10);
		while (pos > buf)
			putchar(*--pos);
	}
	typedef pair<int, int> pii;
	const int N = 1e3 + 10;
	int n, d[N];
	bool vis[N][N];
	class bitset
	{
	private:
		const static int B = 32, BB = 5;
		unsigned data[N / B + 10];
		int len;
		static int ct[1 << (B >> 1)];
		static bool flag;
	public:
		bitset(const int n = 0)
		{
			memset(data, 0, sizeof(data));
			len = n / 32 + 1;
			if (!flag)
			{
				flag = true;
				for (int i = 0; i < (1 << (B >> 1)); i++)
					ct[i] = ct[i >> 1] + (i & 1);
			}
		}
		void set(const int p)
		{
			data[p >> BB] |= (1U << (p & (B - 1)));
		}
		void reset(const int p)
		{
			data[p >> BB] &= ~(1U << (p & (B - 1)));
		}
		bool operator [] (const unsigned p) const
		{
			return data[p >> BB] & (1U << (p & (B - 1)));
		}
		bitset operator & (const bitset &b) const
		{
			bitset ans(len);
			for (int i = 0; i < len; i++)
				ans.data[i] = (data[i] & b.data[i]);
			return ans;
		}
		int count() const
		{
			int ans = 0;
			for (int i = 0; i < len; i++)
				ans += ct[data[i] >> (B >> 1)] + ct[data[i] & (B - 1)];
			return ans;
		}
		int first() const
		{
			for (int i = 0; i < len; i++)
				if (data[i])
				{
					int ans = (i << BB), tmp = data[i];
					while (!(tmp & 1))
						tmp >>= 1, ++ans;
					return ans;
				}
		}
	}bs[N];
	int bitset::ct[1 << (bitset::B >> 1)];
	bool bitset::flag;
	pii e[N];
	int work()
	{
		read(n);
		for (int i = 1; i <= n; i++)
		{
			int k;
			read(k);
			while (k--)
			{
				int a;
				read(a);
				bs[i].set(a);
			}
		}
		int cnt = 0;
		for (int i = 1; i <= n; i++)
			for (int j = i + 1; j <= n; j++)
			{
				bitset tmp = (bs[i] & bs[j]);
				if (tmp.count() == 2)
				{
					int a = tmp.first();
					tmp.reset(a);
					int b = tmp.first();
					if (!vis[a][b])
					{
						printf("%d %d\n", a, b);
						e[cnt++] = pii(a, b);
						++d[a], ++d[b];
						vis[a][b] = vis[b][a] = true;
					}
				}
			}
		if (!cnt)
		{
			for (int i = 2; i <= n; i++)
				printf("%d %d\n", 1, i);
		}
		else if (cnt == 1)
		{
			for (int i = 1; i <= n; i++)
				if (bs[i].count() < n)
				{
					for (int j = 1; j <= n; j++)
						if (!d[j])
						{
							if (bs[i][j])
								printf("%d %d\n", e[0].first, j);
							else
								printf("%d %d\n", e[0].second, j);
						}
					break;
				}
		}
		else
		{
			for (int i = 1; i <= n; i++)
				if (!d[i])
				{
					static int deg[N];
					bitset b;
					bool flag = false;
					memset(deg, 0, sizeof(int[n + 1]));
					for (int j = 1; j <= n; j++)
						if (bs[j][i])
						{
							if (flag)
								b = (b & bs[j]);
							else
								b = bs[j], flag = true;
						}
					for (int j = 0; j < cnt; j++)
						if (b[e[j].first] && b[e[j].second])
							++deg[e[j].first], ++deg[e[j].second];
					for (int j = 1, c = b.count(); j <= n; j++)
						if (b[j])
						{
							if (c == 2)
							{
								if (d[j] == 1)
									printf("%d %d\n", i, j);
							}
							else
							{
								if (deg[j] > 1)
									printf("%d %d\n", i, j);
							}
						}
				}
		}
		return 0;
	}
}
int main()
{
	return zyt::work();
}


#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
using namespace std;

namespace zyt
{
	template<typename T>
	inline bool read(T &x)
	{
		char c;
		bool f = false;
		x = 0;
		do
			c = getchar();
		while (c != EOF && c != '-' && !isdigit(c));
		if (c == EOF)
			return false;
		if (c == '-')
			f = true, c = getchar();
		do
			x = x * 10 + c - '0', c = getchar();
		while (isdigit(c));
		if (f)
			x = -x;
		return true;
	}
	template<typename T>
	inline void write(T x)
	{
		static char buf[20];
		char *pos = buf;
		if (x < 0)
			putchar('-'), x = -x;
		do
			*pos++ = x % 10 + '0';
		while (x /= 10);
		while (pos > buf)
			putchar(*--pos);
	}
	typedef pair<int, int> pii;
	const int N = 1e3 + 10;
	int n, d[N];
	bool vis[N][N];
	class bitset
	{
	private:
		const static int B = 32, BB = 5;
		unsigned data[N / B + 10];
		int len;
		static int ct[1 << (B >> 1)];
		static bool flag;
	public:
		bitset(const int n = 0)
		{
			memset(data, 0, sizeof(data));
			len = n / 32 + 1;
			if (!flag)
			{
				flag = true;
				for (int i = 0; i < (1 << (B >> 1)); i++)
					ct[i] = ct[i >> 1] + (i & 1);
			}
		}
		void set(const int p)
		{
			data[p >> BB] |= (1U << (p & (B - 1)));
		}
		void reset(const int p)
		{
			data[p >> BB] &= ~(1U << (p & (B - 1)));
		}
		bool operator [] (const unsigned p) const
		{
			return data[p >> BB] & (1U << (p & (B - 1)));
		}
		bitset operator & (const bitset &b) const
		{
			bitset ans(len);
			for (int i = 0; i < len; i++)
				ans.data[i] = (data[i] & b.data[i]);
			return ans;
		}
		int count() const
		{
			int ans = 0;
			for (int i = 0; i < len; i++)
				ans += ct[data[i] >> (B >> 1)] + ct[data[i] & ((1 << (B >> 1)) - 1)];
			return ans;
		}
		int first() const
		{
			for (int i = 0; i < len; i++)
				if (data[i])
				{
					int ans = (i << BB), tmp = data[i];
					while (!(tmp & 1))
						tmp >>= 1, ++ans;
					return ans;
				}
		}
	}bs[N];
	int bitset::ct[1 << (bitset::B >> 1)];
	bool bitset::flag;
	pii e[N];
	int work()
	{
		read(n);
		for (int i = 1; i <= n; i++)
		{
			int k;
			read(k);
			bs[i] = bitset(n);
			while (k--)
			{
				int a;
				read(a);
				bs[i].set(a);
			}
		}
		int cnt = 0;
		for (int i = 1; i <= n; i++)
			for (int j = i + 1; j <= n; j++)
			{
				bitset tmp = (bs[i] & bs[j]);
				if (tmp.count() == 2)
				{
					int a = tmp.first();
					tmp.reset(a);
					int b = tmp.first();
					if (!vis[a][b])
					{
						printf("%d %d\n", a, b);
						e[cnt++] = pii(a, b);
						++d[a], ++d[b];
						vis[a][b] = vis[b][a] = true;
					}
				}
			}
		if (!cnt)
		{
			for (int i = 2; i <= n; i++)
				printf("%d %d\n", 1, i);
		}
		else if (cnt == 1)
		{
			for (int i = 1; i <= n; i++)
				if (bs[i].count() < n)
				{
					for (int j = 1; j <= n; j++)
						if (!d[j])
						{
							if (bs[i][j])
								printf("%d %d\n", e[0].first, j);
							else
								printf("%d %d\n", e[0].second, j);
						}
					break;
				}
		}
		else
		{
			for (int i = 1; i <= n; i++)
				if (!d[i])
				{
					static int deg[N];
					bitset b;
					bool flag = false;
					memset(deg, 0, sizeof(int[n + 1]));
					for (int j = 1; j <= n; j++)
						if (bs[j][i])
						{
							if (flag)
								b = (b & bs[j]);
							else
								b = bs[j], flag = true;
						}
					for (int j = 0; j < cnt; j++)
						if (b[e[j].first] && b[e[j].second])
							++deg[e[j].first], ++deg[e[j].second];
					for (int j = 1, c = b.count(); j <= n; j++)
						if (b[j])
						{
							if (c == 2)
							{
								if (d[j] == 1)
									printf("%d %d\n", i, j);
							}
							else
							{
								if (deg[j] > 1)
									printf("%d %d\n", i, j);
							}
						}
				}
		}
		return 0;
	}
}
int main()
{
	return zyt::work();
}


#include<cstdio>
#include<bitset>
using namespace std;
#define N 1056
bitset<N> s[N],v[N],t,v2[N],p;
int n,a,b,is[N],fg[N][N],f1,f2;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a);
		while(a--)scanf("%d",&b),s[i].set(b,1);
		v[i].set(i,1);
	}
	for(int i=1;i<=n;i++)
	for(int j=i+1;j<=n;j++)
	{
		t=s[i]&s[j];
		if(t.count()==2)
		{
			int s1=-1,s2=0;
			for(int k=1;k<=n;k++)
			if(t[k])
			{
				if(s1==-1)s1=k;
				else s2=k;
			}
			if(fg[s1][s2])continue;
			printf("%d %d\n",s1,s2);f1=s1,f2=s2;
			v[s1].set(s2,1);
			v[s2].set(s1,1);
			is[s1]=is[s2]=fg[s1][s2]=fg[s2][s1]=1;
			p.set(s1,1);p.set(s2,1);
		}
	}
	if(p.count()==2)
	{
		int m1=0,m2=0,v1;
		for(int i=1;i<=n;i++)
		{
			int vl=s[i].count();
			if(vl>m1)m1=vl,v1=i;
			else if(vl>m2)m2=vl;
		}
		for(int i=1;i<=n;i++)if(!is[i]){if(s[i][v1])printf("%d %d\n",i,f1);
		else printf("%d %d\n",i,f2);}
		return 0;
	}
	for(int i=1;i<=n;i++)if(!is[i])
	for(int j=1;j<=n;j++)if(is[j])
	if(((s[i]&p)&v[j]).count()==v[j].count())
	{printf("%d %d\n",i,j);break;}
}


#include<cstdio>
#include<bitset>
using namespace std;
#define N 1056
bitset<N> s[N],v[N],t,p;
int n,a,b,is[N],fg[N][N],f1,f2;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a);
		while(a--)scanf("%d",&b),s[i].set(b,1);
		v[i].set(i,1);
	}
	for(int i=1;i<=n;i++)
	for(int j=i+1;j<=n;j++)
	{
		t=s[i]&s[j];
		if(t.count()==2)
		{
			int s1=-1,s2=0;
			for(int k=1;k<=n;k++)
			if(t[k])
			{
				if(s1==-1)s1=k;
				else s2=k;
			}
			if(fg[s1][s2])continue;
			printf("%d %d\n",s1,s2);f1=s1,f2=s2;
			v[s1].set(s2,1);
			v[s2].set(s1,1);
			is[s1]=is[s2]=fg[s1][s2]=fg[s2][s1]=1;
			p.set(s1,1);p.set(s2,1);
		}
	}
	if(!p.count())
	{
		for(int i=2;i<=n;i++)printf("1 %d\n",i);
		return 0;
	}
	if(p.count()==2)
	{
		int m1=0,m2=0,v1;
		for(int i=1;i<=n;i++)
		{
			int vl=s[i].count();
			if(vl>m1)m1=vl,v1=i;
			else if(vl>m2)m2=vl;
		}
		for(int i=1;i<=n;i++)if(!is[i]){if(s[i][v1])printf("%d %d\n",i,f1);
		else printf("%d %d\n",i,f2);}
		return 0;
	}
	for(int i=1;i<=n;i++)
	if(!is[i])
	{
		int as=0,mn=1e9;
		for(int j=1;j<=n;j++)
		if(s[j][i]&&(s[j]&p).count()<mn)
		mn=(s[j]&p).count(),as=j;
		for(int j=1;j<=n;j++)
		if(v[j]==(s[as]&p))
		{printf("%d %d\n",i,j);break;}
	}
}


#include<cstdio>
#include<bitset>
using namespace std;
#define N 1056
bitset<N> s[N],v[N],t,p;
int n,a,b,is[N],fg[N][N],f1,f2;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a);
		while(a--)scanf("%d",&b),s[i].set(b,1);
		v[i].set(i,1);
	}
	for(int i=1;i<=n;i++)
	for(int j=i+1;j<=n;j++)
	{
		t=s[i]&s[j];
		if(t.count()==2)
		{
			int s1=-1,s2=0;
			for(int k=1;k<=n;k++)
			if(t[k])
			{
				if(s1==-1)s1=k;
				else s2=k;
			}
			if(fg[s1][s2])continue;
			printf("%d %d\n",s1,s2);f1=s1,f2=s2;
			v[s1].set(s2,1);
			v[s2].set(s1,1);
			is[s1]=is[s2]=fg[s1][s2]=fg[s2][s1]=1;
			p.set(s1,1);p.set(s2,1);
		}
	}
	if(!p.count())
	{
		for(int i=2;i<=n;i++)printf("1 %d\n",i);
		return 0;
	}
	if(p.count()==2)
	{
		int m1=0,m2=0,v1,ct=1;
		for(int i=1;i<=n;i++)
		{
			int vl=s[i].count();
			if(vl>m1)m1=vl,v1=i;
			else if(vl>m2)m2=vl;
		}
		for(int i=1;i<=n;i++)if(s[i].count()!=n){
		while(is[ct])ct++;
		if(s[i][v1])printf("%d %d\n",ct,f1);
		else printf("%d %d\n",ct,f2);ct++;}
		return 0;
	}
	for(int i=1;i<=n;i++)
	if(!is[i])
	{
		int as=0,mn=1e9;
		for(int j=1;j<=n;j++)
		if(s[j][i]&&(s[j]&p).count()<mn)
		mn=(s[j]&p).count(),as=j;
		for(int j=1;j<=n;j++)
		if(v[j]==(s[as]&p))
		{printf("%d %d\n",i,j);break;}
	}
}


#include<cstdio>
#include<bitset>
using namespace std;
#define N 1056
bitset<N> s[N],v[N],t,p;
int n,a,b,is[N],fg[N][N],f1,f2;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a);
		while(a--)scanf("%d",&b),s[i].set(b,1);
		v[i].set(i,1);
	}
	for(int i=1;i<=n;i++)
	for(int j=i+1;j<=n;j++)
	{
		t=s[i]&s[j];
		if(t.count()==2)
		{
			int s1=-1,s2=0;
			for(int k=1;k<=n;k++)
			if(t[k])
			{
				if(s1==-1)s1=k;
				else s2=k;
			}
			if(fg[s1][s2])continue;
			printf("%d %d\n",s1,s2);f1=s1,f2=s2;
			v[s1].set(s2,1);
			v[s2].set(s1,1);
			is[s1]=is[s2]=fg[s1][s2]=fg[s2][s1]=1;
			p.set(s1,1);p.set(s2,1);
		}
	}
	if(!p.count())
	{
		for(int i=2;i<=n;i++)printf("1 %d\n",i);
		return 0;
	}
	if(p.count()==2)
	{
		int m1=0,m2=0,v1;
		for(int i=1;i<=n;i++)
		{
			int vl=s[i].count();
			if(vl>m1)m1=vl,v1=i;
			else if(vl>m2)m2=vl;
		}
		for(int i=1;i<=n;i++)if(!is[i]){if(s[i][v1])printf("%d %d\n",i,f1);
		else printf("%d %d\n",i,f2);}
		return 0;
	}
	int st=1;
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)if(is[j])
	if(((s[i]&p)&v[j])==(s[i]&p))
	{while(is[st])st++;printf("%d %d\n",st,j);st++;break;}
}


#include<cstdio>
#include<bitset>
using namespace std;
#define N 1056
bitset<N> s[N],v[N],t,p;
int n,a,b,is[N],fg[N][N],f1,f2;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a);
		while(a--)scanf("%d",&b),s[i].set(b,1);
		v[i].set(i,1);
	}
	for(int i=1;i<=n;i++)
	for(int j=i+1;j<=n;j++)
	{
		t=s[i]&s[j];
		if(t.count()==2)
		{
			int s1=-1,s2=0;
			for(int k=1;k<=n;k++)
			if(t[k])
			{
				if(s1==-1)s1=k;
				else s2=k;
			}
			if(fg[s1][s2])continue;
			printf("%d %d\n",s1,s2);f1=s1,f2=s2;
			v[s1].set(s2,1);
			v[s2].set(s1,1);
			is[s1]=is[s2]=fg[s1][s2]=fg[s2][s1]=1;
			p.set(s1,1);p.set(s2,1);
		}
	}
	if(!p.count())
	{
		for(int i=2;i<=n;i++)printf("1 %d\n",i);
		return 0;
	}
	if(p.count()==2)
	{
		int m1=0,m2=0,v1,fg=-1;
		for(int i=1;i<=n;i++)
		{
			int vl=s[i].count();
			if(vl>m1)m1=vl,v1=i;
			else if(vl>m2)m2=vl;
		}
		for(int i=1;i<=n;i++)if(s[i].count()!=n){
		int as=0;
		for(int j=1;j<=n;j++)if(s[i][j]&&j!=f1&&j!=f2&&!is[j])as=j;
		if(fg==-1)fg=as;
		if(s[i][fg])printf("%d %d\n",as,f1);
		else printf("%d %d\n",as,f2);is[as]=1;}
		return 0;
	}
	for(int i=1;i<=n;i++)
	if(!is[i])
	{
		int as=0,mn=1e9;
		for(int j=1;j<=n;j++)
		if(s[j][i]&&(s[j]&p).count()<mn)
		mn=(s[j]&p).count(),as=j;
		for(int j=1;j<=n;j++)
		if(v[j]==(s[as]&p))
		{printf("%d %d\n",i,j);break;}
	}
}//orz


#include<cstdio>
#include<bitset>
using namespace std;
#define N 1056
bitset<N> s[N],v[N],t,v2[N],p;
int n,a,b,is[N],fg[N][N],f1,f2;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a);
		while(a--)scanf("%d",&b),s[i].set(b,1);
		v[i].set(i,1);
	}
	for(int i=1;i<=n;i++)
	for(int j=i+1;j<=n;j++)
	{
		t=s[i]&s[j];
		if(t.count()==2)
		{
			int s1=-1,s2=0;
			for(int k=1;k<=n;k++)
			if(t[k])
			{
				if(s1==-1)s1=k;
				else s2=k;
			}
			if(fg[s1][s2])continue;
			printf("%d %d\n",s1,s2);f1=s1,f2=s2;
			v[s1].set(s2,1);
			v[s2].set(s1,1);
			is[s1]=is[s2]=fg[s1][s2]=fg[s2][s1]=1;
			p.set(s1,1);p.set(s2,1);
		}
	}
	if(!p.count())
	{
		for(int i=2;i<=n;i++)printf("1 %d\n",i);
		return 0;
	}
	if(p.count()==2)
	{
		int m1=0,m2=0,v1;
		for(int i=1;i<=n;i++)
		{
			int vl=s[i].count();
			if(vl>m1)m1=vl,v1=i;
			else if(vl>m2)m2=vl;
		}
		for(int i=1;i<=n;i++)if(!is[i]){if(s[i][v1])printf("%d %d\n",i,f1);
		else printf("%d %d\n",i,f2);}
		return 0;
	}
	for(int i=1;i<=n;i++)if(!is[i])
	for(int j=1;j<=n;j++)if(is[j])
	if(((s[i]&p)&v[j]).count()==v[j].count())
	{printf("%d %d\n",i,j);break;}
}


#include<cstdio>
#include<bitset>
using namespace std;
#define N 1056
bitset<N> s[N],v[N],t,p;
int n,a,b,is[N],fg[N][N],f1,f2;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a);
		while(a--)scanf("%d",&b),s[i].set(b,1);
		v[i].set(i,1);
	}
	for(int i=1;i<=n;i++)
	for(int j=i+1;j<=n;j++)
	{
		t=s[i]&s[j];
		if(t.count()==2)
		{
			int s1=-1,s2=0;
			for(int k=1;k<=n;k++)
			if(t[k])
			{
				if(s1==-1)s1=k;
				else s2=k;
			}
			if(fg[s1][s2])continue;
			printf("%d %d\n",s1,s2);f1=s1,f2=s2;
			v[s1].set(s2,1);
			v[s2].set(s1,1);
			is[s1]=is[s2]=fg[s1][s2]=fg[s2][s1]=1;
			p.set(s1,1);p.set(s2,1);
		}
	}
	if(!p.count())
	{
		for(int i=2;i<=n;i++)printf("1 %d\n",i);
		return 0;
	}
	if(p.count()==2)
	{
		int m1=0,m2=0,v1,fg=-1;
		for(int i=1;i<=n;i++)
		{
			int vl=s[i].count();
			if(vl>m1)m1=vl,v1=i;
			else if(vl>m2)m2=vl;
		}
		for(int i=1;i<=n;i++)if(s[i].count()!=n){
		int as=0;
		for(int j=1;j<=n;j++)if(s[i][j]&&j!=f1&&j!=f2&&!is[j])as=j;
		if(fg==-1)fg=as;
		if(s[i][fg])printf("%d %d\n",as,f1);
		else printf("%d %d\n",as,f2);is[as]=1;}
		return 0;
	}
	for(int i=1;i<=n;i++)
	if(!is[i])
	{
		int as=0,mn=1e9;
		for(int j=1;j<=n;j++)
		if(s[j][i]&&(s[j]&p).count()<mn)
		mn=(s[j]&p).count(),as=j;
		for(int j=1;j<=n;j++)
		if(v[j]==(s[as]&p))
		{printf("%d %d\n",i,j);break;}
	}
}//WA*15


#include<cstdio>
#include<bitset>
using namespace std;
#define N 1056
bitset<N> s[N],v[N],t,p;
int n,a,b,is[N],fg[N][N],f1,f2;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a);
		while(a--)scanf("%d",&b),s[i].set(b,1);
		v[i].set(i,1);
	}
	for(int i=1;i<=n;i++)
	for(int j=i+1;j<=n;j++)
	{
		t=s[i]&s[j];
		if(t.count()==2)
		{
			int s1=-1,s2=0;
			for(int k=1;k<=n;k++)
			if(t[k])
			{
				if(s1==-1)s1=k;
				else s2=k;
			}
			if(fg[s1][s2])continue;
			printf("%d %d\n",s1,s2);f1=s1,f2=s2;
			v[s1].set(s2,1);
			v[s2].set(s1,1);
			is[s1]=is[s2]=fg[s1][s2]=fg[s2][s1]=1;
			p.set(s1,1);p.set(s2,1);
		}
	}
	if(!p.count())
	{
		for(int i=2;i<=n;i++)printf("1 %d\n",i);
		return 0;
	}
	if(p.count()==2)
	{
		int m1=0,m2=0,v1;
		for(int i=1;i<=n;i++)
		{
			int vl=s[i].count();
			if(vl>m1)m1=vl,v1=i;
			else if(vl>m2)m2=vl;
		}
		for(int i=1;i<=n;i++)if(s[i].count()!=n){
		int as=0;
		for(int j=1;j<=n;j++)if(s[i][j]&&j!=f1&&j!=f2)as=j;
		if(s[i][v1])printf("%d %d\n",as,f1);
		else printf("%d %d\n",as,f2);}
		return 0;
	}
	for(int i=1;i<=n;i++)
	if(!is[i])
	{
		int as=0,mn=1e9;
		for(int j=1;j<=n;j++)
		if(s[j][i]&&(s[j]&p).count()<mn)
		mn=(s[j]&p).count(),as=j;
		for(int j=1;j<=n;j++)
		if(v[j]==(s[as]&p))
		{printf("%d %d\n",i,j);break;}
	}
}//1


#include<cstdio>
#include<bitset>
using namespace std;
#define N 1056
bitset<N> s[N],v[N],t,v2[N],p;
int n,a,b,is[N],fg[N][N],f1,f2;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a);
		while(a--)scanf("%d",&b),s[i].set(b,1);
		v[i].set(i,1);
	}
	for(int i=1;i<=n;i++)
	for(int j=i+1;j<=n;j++)
	{
		t=s[i]&s[j];
		if(t.count()==2)
		{
			int s1=-1,s2=0;
			for(int k=1;k<=n;k++)
			if(t[k])
			{
				if(s1==-1)s1=k;
				else s2=k;
			}
			if(fg[s1][s2])continue;
			printf("%d %d\n",s1,s2);f1=s1,f2=s2;
			v[s1].set(s2,1);
			v[s2].set(s1,1);
			is[s1]=is[s2]=fg[s1][s2]=fg[s2][s1]=1;
			p.set(s1,1);p.set(s2,1);
		}
	}
	if(!p.count())
	{
		for(int i=2;i<=n;i++)printf("1 %d\n",i);
		return 0;
	}
	if(p.count()==2)
	{
		int m1=0,m2=0,v1;
		for(int i=1;i<=n;i++)
		{
			int vl=s[i].count();
			if(vl>m1)m1=vl,v1=i;
			else if(vl>m2)m2=vl;
		}
		for(int i=1;i<=n;i++)if(!is[i]){if(s[i][v1])printf("%d %d\n",i,f1);
		else printf("%d %d\n",i,f2);}
		return 0;
	}
	for(int i=1;i<=n;i++)if(!is[i])
	for(int j=1;j<=n;j++)if(is[j])
	if(((s[i]&p)&v[j])==(s[i]&p))
	{printf("%d %d\n",i,j);break;}
}


#include<cstdio>
#include<bitset>
using namespace std;
#define N 1056
bitset<N> s[N],v[N],t,p;
int n,a,b,is[N],fg[N][N],f1,f2;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a);
		while(a--)scanf("%d",&b),s[i].set(b,1);
		v[i].set(i,1);
	}
	for(int i=1;i<=n;i++)
	for(int j=i+1;j<=n;j++)
	{
		t=s[i]&s[j];
		if(t.count()==2)
		{
			int s1=-1,s2=0;
			for(int k=1;k<=n;k++)
			if(t[k])
			{
				if(s1==-1)s1=k;
				else s2=k;
			}
			if(fg[s1][s2])continue;
			printf("%d %d\n",s1,s2);f1=s1,f2=s2;
			v[s1].set(s2,1);
			v[s2].set(s1,1);
			is[s1]=is[s2]=fg[s1][s2]=fg[s2][s1]=1;
			p.set(s1,1);p.set(s2,1);
		}
	}
	if(!p.count())
	{
		for(int i=2;i<=n;i++)printf("1 %d\n",i);
		return 0;
	}
	if(p.count()==2)
	{
		int m1=0,m2=0,v1;
		for(int i=1;i<=n;i++)
		{
			int vl=s[i].count();
			if(vl>m1)m1=vl,v1=i;
			else if(vl>m2)m2=vl;
		}
		for(int i=1;i<=n;i++)if(s[i].count()!=n){
		int as=0;
		for(int j=1;j<=n;j++)if(s[i][j]&&j!=f1&&j!=f2&&!is[j])as=j;
		if(s[i][v1])printf("%d %d\n",as,f1);
		else printf("%d %d\n",as,f2);is[as]=1;}
		return 0;
	}
	for(int i=1;i<=n;i++)
	if(!is[i])
	{
		int as=0,mn=1e9;
		for(int j=1;j<=n;j++)
		if(s[j][i]&&(s[j]&p).count()<mn)
		mn=(s[j]&p).count(),as=j;
		for(int j=1;j<=n;j++)
		if(v[j]==(s[as]&p))
		{printf("%d %d\n",i,j);break;}
	}
}


#include <bits/stdc++.h>
using namespace std;
#define N 1010
inline int read() {
    int x=0;
    char ch=getchar();
    while (!isdigit(ch)) ch=getchar();
    while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    return x;
}
int f[N];
inline int find(int x) {
    return (f[x]==x)?(x):(f[x]=find(f[x]));
}
bitset<N> a[N],b[N],vis;
int main() {
    int n=read(),cnt=0;
    for (int i=1;i<=n;i++) {
        int k=read(); f[i]=i;
        while (k--) a[i][read()]=1;
    }
    bitset<N> w;
    for (int i=1;i<=n;i++) {
        for (int j=1;j<=n;j++) {
            w=a[i]&a[j];
            if (w.count()!=2) continue;
            int u=0,v=0;
            for (int k=1;k<=n;k++)
                if (w[k]) (u?v:u)=k;
            if (find(u)==find(v)) continue;
            f[find(u)]=f[find(v)];
            printf("%d %d\n",u,v),cnt++;
            b[u][u]=b[u][v]=b[v][v]=b[v][u]=vis[u]=vis[v]=1;
        }
    }
    if (!cnt) {
        for (int i=2;i<=n;i++) printf("1 %d\n",i);
        return 0;
    }
    if (cnt==1) {
        // puts("qwq");
        int u=0,v=0;
        for (int i=1;i<=n;i++) if (vis[i]) (u?v:u)=i;
        for (int i=1;i<=n;i++) if (a[i].count()<n) {
            for (int j=1;j<=n;j++) if (!vis[j])
                printf("%d %d\n",a[i][j]?u:v,j);
            return 0;
        }
    }
    for (int i=1;i<=n;i++) if (!vis[i]) {
        int Min=2147483647;
        for (int j=1;j<=n;j++)
            if (a[j][i] && (a[j]&vis).count()<Min)
                w=(a[j]&vis),Min=w.count();
        for (int j=1;j<=n;j++)
            if (w[j] && b[j]==w) {
                printf("%d %d\n",i,j); break;
            }
    }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define N 1010
inline int read() {
    int x=0;
    char ch=getchar();
    while (!isdigit(ch)) ch=getchar();
    while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    return x;
}
int f[N],vis[N];
inline int find(int x) {
    return (f[x]==x)?(x):(f[x]=find(f[x]));
}
bitset<N> a[N],b[N];
int main() {
    int n=read(),cnt=0;
    for (int i=1;i<=n;i++) {
        int k=read(); f[i]=i;
        while (k--) a[i][read()]=1;
    }
    bitset<N> w;
    for (int i=1;i<=n;i++) {
        for (int j=1;j<=n;j++) {
            w=a[i]&a[j];
            if (w.count()!=2) continue;
            int u=0,v=0;
            for (int k=1;k<=n;k++)
                if (w[k]) (u?v:u)=k;
            if (find(u)==find(v)) continue;
            f[find(u)]=f[find(v)];
            printf("%d %d\n",u,v),cnt++;
            b[u][u]=b[u][v]=b[v][v]=b[v][v]=vis[u]=vis[v]=1;
        }
    }
    if (!cnt) {
        for (int i=2;i<=n;i++) printf("1 %d\n",i);
        return 0;
    }
    if (cnt==1) {
        // puts("qwq");
        int u=0,v=0;
        for (int i=1;i<=n;i++) if (vis[i]) (u?v:u)=i;
        for (int i=1;i<=n;i++) if (a[i].count()<n) {
            for (int j=1;j<=n;j++) if (!vis[j])
                printf("%d %d\n",a[i][j]?u:v,j);
            return 0;
        }
    }
    for (int i=1;i<=n;i++) if (!vis[i]) {
        for (int j=1;j<=n;j++) if (a[j][i]) {
            for (int k=1;k<=n;k++) if (vis[k] && a[j]==b[k]) printf("%d %d\n",i,k);
        }
    }
    return 0;
}


#include<bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=1010;
int n,m,fl[N];
int read(){
    int x=0,c;
    while(!isdigit(c=getchar()));
    while(isdigit(c))x=x*10+c-48,c=getchar();
    return x;
}
bitset<N>b[N],p,c[N],is,q;
vector<int>v[N];
int main(){
    // p.set(1);p.set(2);
    // cout<<p._Find_next(2);
    n=read();
    if(n==2)puts("1 2"),exit(0);
    for(int i=1,k;i<=n;i++)
        for(k=read(),k==n&&++m;k--;)
            b[i].set(read());
    if(m==n){
        for(int i=2;i<=n;i++)printf("1 %d\n",i);exit(0);
    }
    if(m==2){
        p.set();for(int i=1;i<=n;i++)p&=b[i];
        int x=p._Find_first(),y=p._Find_next(x);
        printf("%d %d\n",x,y);
        for(int i=1;i<=n;i++)if(b[i].count()!=n){p=b[i];break;}
        for(int i=1;i<=n;i++)if(i!=x&&i!=y)
            printf("%d %d\n",i,p[i]?x:y);
        exit(0);
    }
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++){
            p=b[i]&b[j];
            if(p.count()!=2)continue;
            int x=p._Find_first(),y=p._Find_next(x);
            if(c[x][y])continue;
            c[x].set(y);c[y].set(x);fl[x]=fl[y]=1;
            v[x].pb(y);
        }
    for(int i=1;i<=n;i++)
        if(fl[i])is.set(i),c[i].set(i);
    for(int i=1;i<=n;i++)if(fl[i]==0){
        int mn=1e9;
        for(int j=1;j<=n;j++)if(b[j][i]&&b[j].count()<mn)mn=b[j].count(),p=b[j];
        q=p&is;
        for(int j=1;j<=n;j++)if(fl[j]==1){
            q=p&is;if(q!=c[j])continue;
            q=q^p;
            for(int k=q._Find_first();k<=n;k=q._Find_next(k))
                v[j].pb(k),fl[k]=2;
            fl[j]=2;
        }
    }
    for(int i=1;i<=n;i++)
        for(int j=0;j<v[i].size();j++)
            printf("%d %d\n",i,v[i][j]);
    return 0;
}


#include<bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=1010;
int n,m,fl[N];
int read(){
    int x=0,c;
    while(!isdigit(c=getchar()));
    while(isdigit(c))x=x*10+c-48,c=getchar();
    return x;
}
bitset<N>b[N],p,c[N],is,q;
vector<int>v[N];
int main(){
    // p.set(1);p.set(2);
    // cout<<p._Find_next(2);
    n=read();
    if(n==2)puts("1 2"),exit(0);
    for(int i=1,k;i<=n;i++)
        for(k=read(),k==n&&++m;k--;)
            b[i].set(read());
    if(m==n){
        for(int i=2;i<=n;i++)printf("1 %d\n",i);exit(0);
    }
    if(m==2){
        p.set();for(int i=1;i<=n;i++)p&=b[i];
        int x=p._Find_first(),y=p._Find_next(x);
        printf("%d %d\n",x,y);
        for(int i=1;i<=n;i++)if(b[i].count()!=n){p=b[i];break;}
        for(int i=1;i<=n;i++)if(i!=x&&i!=y)
            printf("%d %d\n",i,p[i]?x:y);
        exit(0);
    }
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++){
            p=b[i]&b[j];
            if(p.count()!=2)continue;
            int x=p._Find_first(),y=p._Find_next(x);
            if(c[x][y])continue;
            c[x].set(y);c[y].set(x);fl[x]=fl[y]=1;
            v[x].pb(y);
        }
    for(int i=1;i<=n;i++)
        if(fl[i])is.set(i),c[i].set(i);
    // for(int i=1;i<=n;i++){
    //     for(int j=1;j<=n;j++)if()
    // }
    for(int i=1;i<=n;i++)if(fl[i]==0){
        int mn=1e9;
        for(int j=1;j<=n;j++)if(b[j][i]&&b[j].count()<mn)mn=b[j].count(),p=b[j];
        q=p&is;
        for(int j=1;j<=n;j++)if(fl[j]==1){
            q=p&is;if(q!=c[j])continue;
            q=q^p;
            for(int k=q._Find_first();k<=n;k=q._Find_next(k))
                v[j].pb(k),fl[k]=2;
            fl[j]=2;
        }
    }
    for(int i=1;i<=n;i++)
        for(int j=0;j<v[i].size();j++)
            printf("%d %d\n",i,v[i][j]);
    return 0;
}
// 6
// 5 1 2 3 4 6
// 6 1 2 3 4 5 6
// 3 2 4 6
// 5 1 2 3 4 5
// 3 2 3 5
// 4 1 2 3 4


#include<bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=1010;
int n,m,fl[N];
int read(){
    int x=0,c;
    while(!isdigit(c=getchar()));
    while(isdigit(c))x=x*10+c-48,c=getchar();
    return x;
}
bitset<N>b[N],p,c[N],is,q;
vector<int>v[N];
int main(){
    // p.set(1);p.set(2);
    // cout<<p._Find_next(2);
    n=read();
    if(n==2)puts("1 2"),exit(0);
    for(int i=1,k;i<=n;i++)
        for(k=read(),k==n&&++m;k--;)
            b[i].set(read());
    if(m==n){
        for(int i=2;i<=n;i++)printf("1 %d\n",i);exit(0);
    }
    if(m==2){
        p.set();for(int i=1;i<=n;i++)p&=b[i];
        int x=p._Find_first(),y=p._Find_next(x);
        printf("%d %d\n",x,y);
        for(int i=1;i<=n;i++)if(b[i].count()!=n){p=b[i];break;}
        for(int i=1;i<=n;i++)if(i!=x&&i!=y)
            printf("%d %d\n",i,p[i]?x:y);
        exit(0);
    }
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++){
            p=b[i]&b[j];
            if(p.count()!=2)continue;
            int x=p._Find_first(),y=p._Find_next(x);
            if(c[x][y])continue;
            c[x].set(y);c[y].set(x);fl[x]=fl[y]=1;
            v[x].pb(y);
        }
    for(int i=1;i<=n;i++)
        if(fl[i])is.set(i),c[i].set(i);
    // for(int i=1;i<=n;i++){
    //     for(int j=1;j<=n;j++)if()
    // }
    for(int i=1;i<=n;i++){
        int mn=1e9;
        for(int j=1;j<=n;j++)if(b[j][i]&&b[j].count()<mn)mn=b[j].count(),p=b[j];
        q=p&is;
        for(int j=1;j<=n;j++)if(fl[j]==1){
            q=p&is;if(q!=c[j])continue;
            q=q^p;
            for(int k=q._Find_first();k<=n;k=q._Find_next(k))
                v[j].pb(k),fl[k]=2;
            fl[j]=2;
        }
    }
    for(int i=1;i<=n;i++)
        for(int j=0;j<v[i].size();j++)
            printf("%d %d\n",i,v[i][j]);
    return 0;
}
// 6
// 5 1 2 3 4 6
// 6 1 2 3 4 5 6
// 3 2 4 6
// 5 1 2 3 4 5
// 3 2 3 5
// 4 1 2 3 4


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
#define mp make_pair
#define PI pair<int,int>
#define poly vector<ll>
#define For(i,l,r) for(int i=(int)(l);i<=(int)(r);i++)
#define Rep(i,r,l) for(int i=(int)(r);i>=(int)(l);i--)
#define pb push_back
#define fi first
#define se second
inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline ll read(){
	ll x = 0; char ch = gc(); bool positive = 1;
	for (; !isdigit(ch); ch = gc())	if (ch == '-')	positive = 0;
	for (; isdigit(ch); ch = gc())	x = x * 10 + ch - '0';
	return positive ? x : -x;
}
inline void write(ll a){
    if(a<0){
    	a=-a; putchar('-');
	}
    if(a>=10)write(a/10);
    putchar('0'+a%10);
}
inline void writeln(ll a){write(a); puts("");}
inline void wri(ll a){write(a); putchar(' ');}
inline ull rnd(){
	return ((ull)rand()<<30^rand())<<4|rand()%4;
}
const int N=1005;
bool vis[N];
bitset<N> s[N],zs;
set<PI> S;
int main(){
	int n=read();
	For(i,1,n){
		int k=read();
		while(k--)s[i][read()]=1;
	}
	For(i,1,n)For(j,i+1,n){
		zs=s[i]&s[j];
		if(zs.count()==2){
			vector<int> v;
			For(j,1,n)if(zs[j])v.pb(j);
			S.insert(mp(v[0],v[1]));
		}
	}
	for(auto i:S){wri(i.fi); writeln(i.se); vis[i.fi]=vis[i.se]=1;}
	if(!S.size()){
		For(i,2,n){
			wri(1); writeln(i);
		}
		return 0;
	}else if(S.size()==1){
		For(i,1,n)if(s[i].count()!=n){
			For(j,1,n)if(!vis[j]){wri(j); writeln(s[i][j]?S.begin()->fi:S.begin()->se);}
			return 0;
		}
		For(i,1,n)if(!vis[i]){wri(i); writeln(S.begin()->fi);}
	}else{
		For(i,1,n){
			vector<int> v;
			For(j,1,n)if(vis[j])v.pb(j);
			if(v.size()==2){
				int c0=0,c1=0;
				For(j,1,n){if(s[j][v[0]])c0++; if(s[j][v[1]])c1++;}
				int cc=c0<c1?v[0]:v[1];
				For(j,1,n)if(!vis[j]&&s[i][j]){
					vis[j]=1; wri(j); writeln(cc);
				}
			}
		}
	}
}


#include<bits/stdc++.h>
using namespace std;
#define ll int
#define llu unsigned long long
#define ld double
#define llu unsigned long long
#define rep(i,x,y)  for(int i=int(x);i<int(y);++i)
#define For(i,x,y)  for(int i=int(x);i<=int(y);++i)
#define FOr(i,x,y)  for(int i=int(x);i>=int(y);--i)
#define pi acos(-1)
#define mk make_pair
#define pa pair<ll,ll>
#define lf else if
#define IL inline
#define sqr(x)      ((x)*(x))
#define Mul(x,y)    ((x)=1LL*(x)*(y)%mod)
#define Add(x,y)    ((x)=((x)+(y))%mod)
#define E(x)        return writeln(x),0
#define LL			(long long)
#define p(x)        printf("~%lld~\n",LL(x))
#define pp(x,y)     printf("~~%lld %lld~~\n",LL(x),LL(y))
#define ppp(x,y,z)  printf("~~~%lld %lld %lld~~~\n",LL(x),LL(y),LL(z))
#define pppp(a,b,c,d)	printf("~~~%lld %lld %lld %lld\n",LL(a),LL(b),LL(c),LL(d))
#define f_in(x)     freopen(x".in","r",stdin)
#define f_out(x)    freopen(x".out","w",stdout)
#define open(x)     f_in(x),f_out(x)
#define fi first
#define se second
#define GuYue		puts("\nGuYueNa________________________________________________________________________________")
#define y1			fafa____
typedef complex<double> E;
namespace SHENZHEBEI{
#ifdef LOCAL
    struct _{_(){freopen("cf.in","r",stdin);}}_;
#endif
#define NEG 1
    static const int GYN=2333333;
    char SZB[GYN],*S=SZB,*T=SZB;
    inline char gc(){   if (S==T){  T=(S=SZB)+fread(SZB,1,GYN,stdin); if (S==T) return '\n';  }   return *S++;    }
#if NEG
    inline ll read(){    ll x=0,g=1; char ch=gc();   for (;!isdigit(ch);ch=gc()) if (ch=='-') g=-1;  for (;isdigit(ch);ch=gc())  x=x*10-48+ch;   return x*g; }
    inline void write(ll x){    if (x<0) putchar('-'),x=-x;  if (x>=10)   write(x/10);    putchar(x%10+'0');  }
#else
    inline ll read(){    ll x=0; char ch=gc();   for (;!isdigit(ch);ch=gc());    for (;isdigit(ch);ch=gc())  x=x*10-48+ch;   return x;   }
    inline void write(ll x){    if (x>=10)   write(x/10);    putchar(x%10+'0');  }
#endif
    inline char readchar(){ char ch=gc();   for(;isspace(ch);ch=gc());  return ch;  }
    inline ll readstr(char *s){ char ch=gc();   int cur=0;  for(;isspace(ch);ch=gc());      for(;!isspace(ch);ch=gc())  s[cur++]=ch;    s[cur]='\0';    return cur; }
	void Print(long long *a,int s,int t){For(i,s,t)printf("%lld ",a[i]);puts("");}
	void Print(int *a,int s,int t){For(i,s,t)printf("%d ",a[i]);puts("");}
	void Print(char *a,int s,int t){For(i,s,t)putchar(a[i]);puts("");}
	void writeln(ll x){write(x),puts("");}
	void rewrite(ll x,ll y){write(x),putchar(' ');writeln(y);}
}using namespace SHENZHEBEI;
const ll N=2010;
ll fa[N],n,cnt,ok[N],rt1,rt2,Cnt;
vector<pa>edge[N];
bitset<1010>a[N];
ll find(ll x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void same(ll x,ll y){fa[find(x)]=find(y);fa[find(x+n)]=find(y+n);}
void unsame(ll x,ll y){fa[find(x)]=find(y+n);fa[find(x+n)]=find(y);}
int main(){
	n=read();
	if (n==1)return 0;
	if (n==2)return puts("1 2"),0;
	For(i,1,n){
		ll sum=read();
		For(j,1,sum)a[read()][i]=1;
	}
	For(i,1,2*n)fa[i]=i;
	For(i,1,n)For(j,i+1,n){
		ll sum=(a[i]&a[j]).count();
		if (sum==1)	same(i,j),++Cnt;
		lf (sum==2)	unsame(i,j),++cnt,ok[i]=ok[j]=1;
		else	edge[sum].push_back(mk(i,j));
	}
	if (!cnt){
		For(i,1,n-1)rewrite(1,i+1);
	}else{
		FOr(sum,n,1)rep(i,0,edge[sum].size()){
			pa to=edge[sum][i];
			ll x=to.fi,y=to.se;
			if (find(x)!=find(y)){
				rewrite(x,y);
				unsame(x,y);
			}
		}
	}
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
#define mp make_pair
#define PI pair<int,int>
#define poly vector<ll>
#define For(i,l,r) for(int i=(int)(l);i<=(int)(r);i++)
#define Rep(i,r,l) for(int i=(int)(r);i>=(int)(l);i--)
#define pb push_back
#define fi first
#define se second
inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline ll read(){
	ll x = 0; char ch = gc(); bool positive = 1;
	for (; !isdigit(ch); ch = gc())	if (ch == '-')	positive = 0;
	for (; isdigit(ch); ch = gc())	x = x * 10 + ch - '0';
	return positive ? x : -x;
}
inline void write(ll a){
    if(a<0){
    	a=-a; putchar('-');
	}
    if(a>=10)write(a/10);
    putchar('0'+a%10);
}
inline void writeln(ll a){write(a); puts("");}
inline void wri(ll a){write(a); putchar(' ');}
inline ull rnd(){
	return ((ull)rand()<<30^rand())<<4|rand()%4;
}
const int N=1005;
bool vis[N];
bitset<N> s[N],xl[N],zs;
set<PI> S;
int main(){
	int n=read();
	For(i,1,n){
		int k=read();
		while(k--)s[i][read()]=1;
	}
	For(i,1,n)For(j,i+1,n){
		zs=s[i]&s[j];
		if(zs.count()==2){
			vector<int> v;
			For(j,1,n)if(zs[j])v.pb(j);
			S.insert(mp(v[0],v[1]));
		}
	}
	for(auto i:S){wri(i.fi); writeln(i.se); vis[i.fi]=vis[i.se]=1;}
	if(!S.size()){
		For(i,2,n){
			wri(1); writeln(i);
		}
		return 0;
	}else if(S.size()==1){
		For(i,1,n)if(s[i].count()!=n){
			For(j,1,n)if(!vis[j]){wri(j); writeln(s[i][j]?S.begin()->fi:S.begin()->se);}
			return 0;
		}
		For(i,1,n)if(!vis[i]){wri(i); writeln(S.begin()->fi);}
	}else{
		for(auto i:S)xl[i.fi][i.se]=xl[i.se][i.fi]=1;
		For(i,1,n)if(vis[i])xl[i][i]=1;
		For(i,1,n)if(!vis[i]){
			bitset<N> jb;
			int k=0;
			For(j,1,n)if(s[j][i]&&(!k||s[j].count()<s[k].count()))k=j;
			For(j,1,n)if(vis[j]&&s[k][j])jb[j]=1;
			For(j,1,n)if(jb==xl[j]){
				wri(j); writeln(i); break;
			}
		}
	}
}
/*
6
5 1 2 3 4 5
6 1 2 3 4 5 6
5 1 2 3 5 6
4 1 2 3 5
3 2 3 6
3 1 2 4

1 2
2 3
1 4
2 5
3 6

*/


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
#define mp make_pair
#define PI pair<int,int>
#define poly vector<ll>
#define For(i,l,r) for(int i=(int)(l);i<=(int)(r);i++)
#define Rep(i,r,l) for(int i=(int)(r);i>=(int)(l);i--)
#define pb push_back
#define fi first
#define se second
inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline ll read(){
	ll x = 0; char ch = gc(); bool positive = 1;
	for (; !isdigit(ch); ch = gc())	if (ch == '-')	positive = 0;
	for (; isdigit(ch); ch = gc())	x = x * 10 + ch - '0';
	return positive ? x : -x;
}
inline void write(ll a){
    if(a<0){
    	a=-a; putchar('-');
	}
    if(a>=10)write(a/10);
    putchar('0'+a%10);
}
inline void writeln(ll a){write(a); puts("");}
inline void wri(ll a){write(a); putchar(' ');}
inline ull rnd(){
	return ((ull)rand()<<30^rand())<<4|rand()%4;
}
const int N=1005;
bool vis[N];
bitset<N> s[N],zs;
set<PI> S;
int main(){
	int n=read();
	For(i,1,n){
		int k=read();
		while(k--)s[i][read()]=1;
	}
	For(i,1,n)For(j,i+1,n){
		zs=s[i]&s[j];
		if(zs.count()==2){
			vector<int> v;
			For(j,1,n)if(zs[j])v.pb(j);
			S.insert(mp(v[0],v[1]));
		}
	}
	for(auto i:S){wri(i.fi); writeln(i.se); vis[i.fi]=vis[i.se]=1;}
	if(!S.size()){
		For(i,2,n){
			wri(1); writeln(i);
		}
		return 0;
	}else if(S.size()==1){
		For(i,1,n)if(!vis[i]){
			For(j,i,n)if(!vis[j]){
				wri(j); writeln(s[j]==s[i]?S.begin()->fi:S.begin()->se);
			}
			return 0;
		}
	}else{
		For(i,1,n)if(!vis[i]){
			int k=0;
			For(j,1,n)if(vis[j]&&(s[j]&s[i])==s[i]){
				if(!k||s[k].count()>s[j].count())k=j;
			}
			wri(k); writeln(i);
		}
	}
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
#define mp make_pair
#define PI pair<int,int>
#define poly vector<ll>
#define For(i,l,r) for(int i=(int)(l);i<=(int)(r);i++)
#define Rep(i,r,l) for(int i=(int)(r);i>=(int)(l);i--)
#define pb push_back
#define fi first
#define se second
inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline ll read(){
	ll x = 0; char ch = gc(); bool positive = 1;
	for (; !isdigit(ch); ch = gc())	if (ch == '-')	positive = 0;
	for (; isdigit(ch); ch = gc())	x = x * 10 + ch - '0';
	return positive ? x : -x;
}
inline void write(ll a){
    if(a<0){
    	a=-a; putchar('-');
	}
    if(a>=10)write(a/10);
    putchar('0'+a%10);
}
inline void writeln(ll a){write(a); puts("");}
inline void wri(ll a){write(a); putchar(' ');}
inline ull rnd(){
	return ((ull)rand()<<30^rand())<<4|rand()%4;
}
const int N=1005;
bool vis[N];
bitset<N> s[N],xl[N],zs;
set<PI> S;
int main(){
	int n=read();
	For(i,1,n){
		int k=read();
		while(k--)s[i][read()]=1;
	}
	For(i,1,n)For(j,i+1,n){
		zs=s[i]&s[j];
		if(zs.count()==2){
			vector<int> v;
			For(j,1,n)if(zs[j])v.pb(j);
			S.insert(mp(v[0],v[1]));
		}
	}
	for(auto i:S){wri(i.fi); writeln(i.se); vis[i.fi]=vis[i.se]=1;}
	if(!S.size()){
		For(i,2,n){
			wri(1); writeln(i);
		}
		return 0;
	}else if(S.size()==1){
		For(i,1,n)if(s[i].count()!=n){
			For(j,1,n)if(!vis[j]){wri(j); writeln(s[i][j]?S.begin()->fi:S.begin()->se);}
			return 0;
		}
		For(i,1,n)if(!vis[i]){wri(i); writeln(S.begin()->fi);}
	}else{
		for(auto i:S)xl[i.fi][i.se]=xl[i.se][i.fi]=1;
		For(i,1,n)if(vis[i])xl[i][i]=1;
		For(i,1,n)if(!vis[i]){
			bitset<N> jb;
			For(j,1,n)if(vis[j]&&s[i][j])jb[j]=1;
			For(j,1,n)if(jb==xl[j]){
				wri(j); writeln(i); break;
			}
		}
	}
}
/*
6
5 1 2 3 4 5
6 1 2 3 4 5 6
5 1 2 3 5 6
3 1 2 4
4 1 2 3 5
3 2 3 6

1 2
2 3
1 4
2 5
3 6

*/


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
#define mp make_pair
#define PI pair<int,int>
#define poly vector<ll>
#define For(i,l,r) for(int i=(int)(l);i<=(int)(r);i++)
#define Rep(i,r,l) for(int i=(int)(r);i>=(int)(l);i--)
#define pb push_back
#define fi first
#define se second
inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline ll read(){
	ll x = 0; char ch = gc(); bool positive = 1;
	for (; !isdigit(ch); ch = gc())	if (ch == '-')	positive = 0;
	for (; isdigit(ch); ch = gc())	x = x * 10 + ch - '0';
	return positive ? x : -x;
}
inline void write(ll a){
    if(a<0){
    	a=-a; putchar('-');
	}
    if(a>=10)write(a/10);
    putchar('0'+a%10);
}
inline void writeln(ll a){write(a); puts("");}
inline void wri(ll a){write(a); putchar(' ');}
inline ull rnd(){
	return ((ull)rand()<<30^rand())<<4|rand()%4;
}
const int N=1005;
bool vis[N];
bitset<N> s[N],zs;
set<PI> S;
int main(){
	int n=read();
	For(i,1,n){
		int k=read();
		while(k--)s[i][read()]=1;
	}
	For(i,1,n)For(j,i+1,n){
		zs=s[i]&s[j];
		if(zs.count()==2){
			vector<int> v;
			For(j,1,n)if(zs[j])v.pb(j);
			S.insert(mp(v[0],v[1]));
		}
	}
	for(auto i:S){wri(i.fi); writeln(i.se); vis[i.fi]=vis[i.se]=1;}
	if(!S.size()){
		For(i,2,n){
			wri(1); writeln(i);
		}
		return 0;
	}else if(S.size()==1){
		For(i,1,n)if(s[i].count()!=n){
			For(j,1,n)if(!vis[j]){wri(j); writeln(s[i][j]?S.begin()->fi:S.begin()->se);}
			return 0;
		}
		For(i,1,n)if(!vis[i]){wri(i); writeln(S.begin()->fi);}
	}else{
		For(i,1,n){
			vector<int> v;
			For(j,1,n)if(vis[j]&&s[i][j])v.pb(j);
			if(v.size()==2){
				int c0=0,c1=0;
				For(j,1,n){if(s[j][v[0]])c0++; if(s[j][v[1]])c1++;}
				int cc=c0<c1?v[0]:v[1];
				For(j,1,n)if(!vis[j]&&s[i][j]){
					vis[j]=1; wri(j); writeln(cc);
				}
			}
		}
	}
}


#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <bitset>
#define N 1025
template <typename T> inline void read(T &x) {
	x = 0; char c = getchar(); bool flag = false;
	while (!isdigit(c)) { if (c == '-')	flag = true; c = getchar(); }
	while (isdigit(c)) { x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); }
	if (flag)	x = -x;
}
using namespace std;
int n, etot;
bitset<N> st[N], neib[N], is_o, tmp;
int id[N];
inline void Get_o() {
	for (register int i = 1; i <= n; ++i) {
		for (register int j = 1; j <= n; ++j) if (j != i) {
			tmp = st[i] & st[j];
			if (tmp.count() == 2) {
				int x = 0, y = 0;
				for (register int k = 1; k <= n; ++k) {
					if (tmp[k]) {
						if (x) { y = k; break; }
						x = k;
					}
				}
				is_o[x] = is_o[y] = true;
				if (!neib[x][y])	neib[x][y] = neib[y][x] = true, ++etot, printf("%d %d\n", x, y);
			}
		}
	}
	for (register int i = 1; i <= n; ++i) {
		if (!is_o[i]) {
			int mn = n + 1;
			for (register int j = 1; j <= n; ++j) if (st[j][i]) {
				int ct = st[j].count();
				if (ct < mn)	mn = ct, id[i] = j;
			}
		}
	}
}

inline void Link_l() {
	for (register int i = 1; i <= n; ++i)	if (is_o[i])	neib[i][i] = true;
	for (register int i = 1; i <= n; ++i) if (!is_o[i]) {
		int nw = id[i];
		for (register int j = 1; j <= n; ++j)	if (st[nw][j] && !is_o[j])	st[nw][j] = false;
		for (register int j = 1; j <= n; ++j) if ((st[nw] ^ neib[j]).count() == 0) {
			printf("%d %d\n", i, j); break;
		}
	}
}

int main() {
	read(n);
	for (register int i = 1; i <= n; ++i) {
		int t; read(t);
		for (register int j = 1; j <= t; ++j) {
			int x; read(x);
			st[i][x] = true;
		}
	}
	if (n == 2) {
		puts("1 2");
		return 0;
	}
	if (n == 3) {
		puts("1 2");
		puts("2 3");
		return 0;
	}
	Get_o();
//	puts("---------");
	if (!etot) {
//		puts("P0");
		for (register int i = 2; i <= n; ++i)	printf("1 %d\n", i);
		return 0;
	} else if (etot == 1) {
//		puts("P1");
		int fl = 1;
		while (is_o[fl])	++fl;
		int x = 0, y = 0;
		for (register int i = 1; i <= n; ++i) if (is_o[i]) {
//			printf("i = %d\n", i);
			if (x) { y = i; break; }
			x = i;
		}
		for (register int i = 1; i <= n; ++i)	if (!is_o[i]) {
			int nw = id[i];
			if (st[nw][fl])	printf("%d %d\n", x, i);
			else	printf("%d %d\n", y, i);
		}
	} else {
		Link_l();
	}
	return 0;
}


#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <bitset>
#define N 1025
template <typename T> inline void read(T &x) {
	x = 0; char c = getchar(); bool flag = false;
	while (!isdigit(c)) { if (c == '-')	flag = true; c = getchar(); }
	while (isdigit(c)) { x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); }
	if (flag)	x = -x;
}
using namespace std;
int n, etot;
bitset<N> st[N], neib[N], is_o, tmp;
int id[N];
inline void Get_o() {
	for (register int i = 1; i <= n; ++i)
		for (register int j = 1; j <= n; ++j) if (j != i) {
			tmp = st[i] & st[j];
			if (tmp.count() == 2) {
				int x = 0, y = 0;
				for (register int k = 1; k <= n; ++k)	if (tmp[k]) {
					if (x) { y = k; break; }
					x = k;
				}
				is_o[x] = is_o[y] = true;
				if (!neib[x][y])	neib[x][y] = neib[y][x] = true, ++etot, printf("%d %d\n", x, y);
			}
		}
	for (register int i = 1; i <= n; ++i)	if (!is_o[i]) {
		int mn = n + 1;
		for (register int j = 1; j <= n; ++j) if (st[j][i]) {
			int ct = st[j].count();
			if (ct < mn)	mn = ct, id[i] = j;
		}
	}
}

inline void Link_l() {
	for (register int i = 1; i <= n; ++i)	if (is_o[i])	neib[i][i] = true;
	for (register int i = 1; i <= n; ++i) if (!is_o[i]) {
		int nw = id[i];
		for (register int j = 1; j <= n; ++j)	if (st[nw][j] && !is_o[j])	st[nw][j] = false;
		for (register int j = 1; j <= n; ++j) if ((st[nw] ^ neib[j]).count() == 0) {
			printf("%d %d\n", i, j); break;
		}
	}
}

int main() {
	read(n);
	for (register int i = 1; i <= n; ++i) {
		int t; read(t);
		for (register int j = 1; j <= t; ++j) {
			int x; read(x);
			st[i][x] = true;
		}
	}
	if (n == 2) {
		puts("1 2");
		return 0;
	}
	if (n == 3) {
		puts("1 2");
		puts("2 3");
		return 0;
	}
	Get_o();
	if (!etot) {
		for (register int i = 2; i <= n; ++i)	printf("1 %d\n", i);
		return 0;
	} else if (etot == 1) {
		int fl = 1;
		while (is_o[fl])	++fl;
		int x = 0, y = 0;
		for (register int i = 1; i <= n; ++i) if (is_o[i]) {
			if (x) { y = i; break; }
			x = i;
		}
		for (register int i = 1; i <= n; ++i)	if (!is_o[i]) {
			int nw = id[i];
			if (st[nw][fl])	printf("%d %d\n", x, i);
			else	printf("%d %d\n", y, i);
		}
	} else	Link_l();
	return 0;
}


		//	   - -- --- ---- -----be name khoda----- ---- --- -- -		\\

#include <bits/stdc++.h>
using namespace std;

inline int in() { int x; scanf("%d", &x); return x; }
const int N = 10, B = 9;

int unity[N][N][2], sz[N], deg[N], n;
bitset <N> s[N], g[N], g2[N], tmp;
bool isLeaf[N], isO[N][N];

void star()
{
	for(int i = 1; i < n; i++)
		cout << "1 " << i + 1 << "\n";
	exit(0);
}

void hack()
{
	int a, b, l;
	vector <int> A, B;
	for(int i = 0; i < n; i++)
	{
		for(int j = 0; j < n; j++)
			if(g[i][j])
			{
				a = i;
				b = j;
			}
		if(isLeaf[i])
			l = i;
	}
	for(int i = 0; i < n; i++)
		if(s[i][l] && sz[i] != n)
		{
			for(int j = 0; j < n; j++)
				if(s[i][j] && isLeaf[j])
				{
					isLeaf[j] = 0;
					A.push_back(j);
				}
			break;
		}
	for(int i = 0; i < n; i++)
		if(isLeaf[i])
			B.push_back(i);
	for(int x : A)
		cout << 1 + x << " " << a + 1 << "\n";
	cout << a + 1 << " " << 1 + b << "\n";
	for(int y : B)
		cout << 1 + y << " " << b + 1 << "\n";
	exit(0);
}

int gav(const bitset <N> &b)
{
	int ind = 0;
	for(int i = B; i >= 0; i--)
		if((b >> (ind + (1 << i))).count())
			ind += (1 << i);
	return ind;
}

int main()
{
	cin >> n;
	for(int i = 0; i < n; i++)
		for(int k = sz[i] = in(); k; k--)
			s[i][in() - 1] = 1;

	fill(isLeaf, isLeaf + n, 1);
	for(int i = 0; i < n; i++)
		for(int j = i + 1; j < n; j++)
		{
			tmp = s[i] & s[j];
			if(tmp.count() != 2)
				continue;
			isO[i][j] = isO[j][i] = 1;
			int a = gav(tmp);
			tmp[a] = 0;
			int b = gav(tmp);
			g[a][b] = g[b][a] = 1;
			isLeaf[a] = isLeaf[b] = 0;
			unity[i][j][0] = a;
			unity[i][j][1] = b;
		}

	int cnt = 0;
	for(int i = 0; i < n; i++)
		for(int j = 0; j < n; j++)
		{
			cnt += g[i][j];
			deg[i] += g[i][j];
		}
	if(!cnt)
		star();
	if(cnt == 2)
		hack();

	for(int i = 0; i < n; i++)
		if(isLeaf[i])
		{
			int b = -1;
			for(int j = 0; j < n; j++)
				if(s[j][i])
					if(b == -1 || sz[j] < sz[b])
						b = j;
			vector <int> kia;
			for(int j = 0; j < n; j++)
				if(s[b][j] && !isLeaf[j])
					kia.push_back(j);
			assert(kia.size() > 1);
			int p;
			if(kia.size() == 2)
				p = (deg[kia[0]] == 1 ? kia[0] : kia[1]);
			else
			{
				tmp.reset();
				for(int x : kia)
					tmp[x] = 1;
				for(int x : kia)
					if((g[x] & tmp).count() == kia.size())
					{
						p = x;
						break;
					}
			}
			g2[p][i] = g2[i][p] = 1;
		}

	for(int i = 0; i < n; i++)
		for(int j = i + 1; j < n; j++)
			if(g[i][j] || g2[i][j])
				cout << 1 + i << " " << j + 1 << "\n";
}


		//	   - -- --- ---- -----be name khoda----- ---- --- -- -		\\

#include <bits/stdc++.h>
using namespace std;

inline int in() { int x; scanf("%d", &x); return x; }
const int N = 1221, B = 9;

int unity[N][N][2], sz[N], deg[N], n;
bitset <N> s[N], g[N], g2[N], tmp;
bool isLeaf[N], isO[N][N];

void star()
{
	for(int i = 1; i < n; i++)
		cout << "1 " << i + 1 << "\n";
	exit(0);
}

void hack()
{
	int a, b, l;
	vector <int> A, B;
	for(int i = 0; i < n; i++)
	{
		for(int j = 0; j < n; j++)
			if(g[i][j])
			{
				a = i;
				b = j;
			}
		if(isLeaf[i])
			l = i;
	}
	for(int i = 0; i < n; i++)
		if(s[i][l] && sz[i] != n)
		{
			for(int j = 0; j < n; j++)
				if(s[i][j] && isLeaf[j])
				{
					isLeaf[j] = 0;
					A.push_back(j);
				}
			break;
		}
	for(int i = 0; i < n; i++)
		if(isLeaf[i])
			B.push_back(i);
	for(int x : A)
		cout << 1 + x << " " << a + 1 << "\n";
	cout << a + 1 << " " << 1 + b << "\n";
	for(int y : B)
		cout << 1 + y << " " << b + 1 << "\n";
	exit(0);
}

int gav(const bitset <N> &b)
{
	int ind = 0;
	for(int i = B; i >= 0; i--)
		if((b >> (ind + (1 << i))).count())
			ind += (1 << i);
	return ind;
}

int main()
{
	cin >> n;
	for(int i = 0; i < n; i++)
		for(int k = sz[i] = in(); k; k--)
			s[i][in() - 1] = 1;

	fill(isLeaf, isLeaf + n, 1);
	for(int i = 0; i < n; i++)
		for(int j = i + 1; j < n; j++)
		{
			tmp = s[i] & s[j];
			if(tmp.count() != 2)
				continue;
			isO[i][j] = isO[j][i] = 1;
			int a = gav(tmp);
			tmp[a] = 0;
			int b = gav(tmp);
			g[a][b] = g[b][a] = 1;
			isLeaf[a] = isLeaf[b] = 0;
			unity[i][j][0] = a;
			unity[i][j][1] = b;
		}

	int cnt = 0;
	for(int i = 0; i < n; i++)
		for(int j = 0; j < n; j++)
		{
			cnt += g[i][j];
			deg[i] += g[i][j];
		}
	if(!cnt)
		star();
	if(cnt == 2)
		hack();

	for(int i = 0; i < n; i++)
		if(isLeaf[i])
		{
			int b = -1;
			for(int j = 0; j < n; j++)
				if(s[j][i])
					if(b == -1 || sz[j] < sz[b])
						b = j;
			vector <int> kia;
			for(int j = 0; j < n; j++)
				if(s[b][j] && !isLeaf[j])
					kia.push_back(j);
			assert(kia.size() > 1);
			int p;
			if(kia.size() == 2)
				p = (deg[kia[0]] == 1 ? kia[0] : kia[1]);
			else
			{
				tmp.reset();
				for(int x : kia)
					tmp[x] = 1;
				for(int x : kia)
					if((g[x] & tmp).count() == kia.size())
					{
						p = x;
						break;
					}
			}
			g2[p][i] = g2[i][p] = 1;
		}

	for(int i = 0; i < n; i++)
		for(int j = i + 1; j < n; j++)
			if(g[i][j] || g2[i][j])
				cout << 1 + i << " " << j + 1 << "\n";
}


		//	   - -- --- ---- -----be name khoda----- ---- --- -- -		\\

#include <bits/stdc++.h>
using namespace std;

inline int in() { int x; scanf("%d", &x); return x; }
const int N = 1221, B = 9;

int unity[N][N][2], sz[N], deg[N], n;
bitset <N> s[N], g[N], g2[N], tmp;
bool isLeaf[N], isO[N][N];

void star()
{
	for(int i = 1; i < n; i++)
		cout << "1 " << i + 1 << "\n";
	exit(0);
}

void hack()
{
	int a, b, l;
	vector <int> A, B;
	for(int i = 0; i < n; i++)
	{
		for(int j = 0; j < n; j++)
			if(g[i][j])
			{
				a = i;
				b = j;
			}
		if(isLeaf[i])
			l = i;
	}
	for(int i = 0; i < n; i++)
		if(s[i][l] && sz[i] != n)
		{
			for(int j = 0; j < n; j++)
				if(s[i][j] && isLeaf[j])
				{
					isLeaf[j] = 0;
					A.push_back(j);
				}
			break;
		}
	for(int i = 0; i < n; i++)
		if(isLeaf[i])
			B.push_back(i);
	for(int x : A)
		cout << 1 + x << " " << a + 1 << "\n";
	cout << a + 1 << " " << 1 + b << "\n";
	for(int y : B)
		cout << 1 + y << " " << b + 1 << "\n";
	exit(0);
}

int gav(const bitset <N> &b)
{
	int ind = 0;
	for(int i = B; i >= 0; i--)
		if((b >> (ind + (1 << i))).count())
			ind += (1 << i);
	return ind;
}

int main()
{
	cin >> n;
	for(int i = 0; i < n; i++)
		for(int k = sz[i] = in(); k; k--)
			s[i][in() - 1] = 1;

	fill(isLeaf, isLeaf + n, 1);
	for(int i = 0; i < n; i++)
		for(int j = i + 1; j < n; j++)
		{
			tmp = s[i] & s[j];
			if(tmp.count() != 2)
				continue;
			isO[i][j] = isO[j][i] = 1;
			int a = gav(tmp);
			tmp[a] = 0;
			int b = gav(tmp);
			g[a][b] = g[b][a] = 1;
			isLeaf[a] = isLeaf[b] = 0;
			unity[i][j][0] = a;
			unity[i][j][1] = b;
		}

	int cnt = 0;
	for(int i = 0; i < n; i++)
		for(int j = 0; j < n; j++)
		{
			cnt += g[i][j];
			deg[i] += g[i][j];
		}
	if(!cnt)
		star();
	if(cnt == 2)
		hack();

	for(int i = 0; i < n; i++)
		if(isLeaf[i])
		{
			int b = -1;
			for(int j = 0; j < n; j++)
				if(s[j][i])
					if(b == -1 || sz[j] < sz[b])
						b = j;
			vector <int> kia;
			for(int j = 0; j < n; j++)
				if(s[b][j] && !isLeaf[j])
					kia.push_back(j);
//			assert(kia.size() > 1);
			int p;
			if(kia.size() == 2)
				p = (deg[kia[0]] == 1 ? kia[0] : kia[1]);
			else
			{
				tmp.reset();
				for(int x : kia)
					tmp[x] = 1;
				for(int x : kia)
					if((g[x] & tmp).count() == kia.size())
					{
						p = x;
						break;
					}
			}
			g2[p][i] = g2[i][p] = 1;
		}

	for(int i = 0; i < n; i++)
		for(int j = i + 1; j < n; j++)
			if(g[i][j] || g2[i][j])
				cout << 1 + i << " " << j + 1 << "\n";
}


		//	   - -- --- ---- -----be name khoda----- ---- --- -- -		\\

#include <bits/stdc++.h>
using namespace std;

inline int in() { int x; scanf("%d", &x); return x; }
const int N = 1221, B = 9;

bitset <N> s[N], g[N], g2[N], tmp;
int sz[N], deg[N], n;
bool isLeaf[N];

void star()
{
	for(int i = 1; i < n; i++)
		cout << "1 " << i + 1 << "\n";
	exit(0);
}

void hack()
{
	int a, b, l;
	vector <int> A, B;
	for(int i = 0; i < n; i++)
	{
		for(int j = 0; j < n; j++)
			if(g[i][j])
			{
				a = i;
				b = j;
			}
		if(isLeaf[i])
			l = i;
	}
	for(int i = 0; i < n; i++)
		if(s[i][l] && sz[i] != n)
		{
			for(int j = 0; j < n; j++)
				if(s[i][j] && isLeaf[j])
				{
					isLeaf[j] = 0;
					A.push_back(j);
				}
			break;
		}
	for(int i = 0; i < n; i++)
		if(isLeaf[i])
			B.push_back(i);
	for(int x : A)
		cout << 1 + x << " " << a + 1 << "\n";
	cout << a + 1 << " " << 1 + b << "\n";
	for(int y : B)
		cout << 1 + y << " " << b + 1 << "\n";
	exit(0);
}

int gav(const bitset <N> &b)
{
	int ind = 0;
	for(int i = B; i >= 0; i--)
		if((b >> (ind + (1 << i))).count())
			ind += (1 << i);
	return ind;
}

int main()
{
	cin >> n;
	for(int i = 0; i < n; i++)
		for(int k = sz[i] = in(); k; k--)
			s[i][in() - 1] = 1;

	fill(isLeaf, isLeaf + n, 1);
	for(int i = 0; i < n; i++)
		for(int j = i + 1; j < n; j++)
		{
			tmp = s[i] & s[j];
			if(tmp.count() != 2)
				continue;
			int a = gav(tmp);
			tmp[a] = 0;
			int b = gav(tmp);
			g[a][b] = g[b][a] = 1;
			isLeaf[a] = isLeaf[b] = 0;
		}

	int cnt = 0;
	for(int i = 0; i < n; i++)
		for(int j = 0; j < n; j++)
		{
			cnt += g[i][j];
			deg[i] += g[i][j];
		}
	if(!cnt)
		star();
	if(cnt == 2)
		hack();

	for(int i = 0; i < n; i++)
		if(isLeaf[i])
		{
			int b = -1;
			for(int j = 0; j < n; j++)
				if(s[j][i])
					if(b == -1 || sz[j] < sz[b])
						b = j;
			vector <int> kia;
			for(int j = 0; j < n; j++)
				if(s[b][j] && !isLeaf[j])
					kia.push_back(j);
			assert(kia.size() > 1);
			int p;
			if(kia.size() == 2)
				p = (deg[kia[0]] == 1 ? kia[0] : kia[1]);
			else
			{
				tmp.reset();
				for(int x : kia)
					tmp[x] = 1;
				for(int x : kia)
					if((g[x] & tmp).count() + 1 == kia.size())
					{
						p = x;
						break;
					}
			}
			g2[p][i] = g2[i][p] = 1;
		}

	for(int i = 0; i < n; i++)
		for(int j = i + 1; j < n; j++)
			if(g[i][j] || g2[i][j])
				cout << 1 + i << " " << j + 1 << "\n";
}


#include <bits/stdc++.h>

#define reg register
#define pr std::pair<int, int>
#define fi first
#define se second
#define FIN(s) freopen(s, "r", stdin)
#define FOUT(s) freopen(s, "w", stdout)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define rep(i, l, r) for (int i = l; i <= r; ++i)
#define lep(i, l, r) for (int i = l; i < r; ++i)
#define irep(i, r, l) for (int i = r; i >= l; --i)
#define ilep(i, r, l) for (int i = r; i > l; --i)
#define Rep(i, n) rep(i, 1, n)
#define Lep(i, n) lep(i, 1, n)
#define IRep(i, n) irep(i, n, 1)
#define ILep(i, n) ilep(i, n, 1)
typedef long long ll;
typedef long double ld;

namespace modular {
    const int MOD = 1000000007;
    inline int add(int x, int y) { return (x += y) >= MOD ? x -= MOD : x; }
    inline void inc(int &x, int y) { (x += y) >= MOD ? x -= MOD : 0; }
    inline int mul(int x, int y) { return 1LL * x * y % MOD; }
    inline int qpow(int x, int y) {
        int ans = 1;
        for (; y; y >>= 1, x = mul(x, x))
            if (y & 1) ans = mul(ans, x);
        return ans;
    }
};  // namespace modular

namespace Base {
    template <typename Tp>
    inline Tp input() {
        Tp x = 0, y = 1;
        char c = getchar();
        while ((c < '0' || '9' < c) && c != EOF) {
            if (c == '-') y = -1;
            c = getchar();
        }
        if (c == EOF) return 0;
        while ('0' <= c && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x *= y;
    }
    template <typename Tp>
    inline void read(Tp &x) {
        x = input<Tp>();
    }
    template <typename Tp>
    inline void chmax(Tp &x, Tp y) {
        x < y ? x = y : 0;
    }
    template <typename Tp>
    inline void chmin(Tp &x, Tp y) {
        x > y ? x = y : 0;
    }
};  // namespace Base
using namespace Base;
/*----------------------------------------------------------------------------*/

#define MAX_N 1007
#define bsn std::bitset<MAX_N>
#define V std::vector

int N, tot;
int vt[MAX_N];
bsn f[MAX_N], g[MAX_N], t[MAX_N], tmp;
bool nlf[MAX_N], flg[MAX_N];

void print(bsn k) {
    puts("----begin----");
    for (int i = k._Find_first(); i != k.size(); i = k._Find_next(i))
        printf("%d ", i);
    puts("");
    puts("----end----");
}

void solve() {
    Rep(i, N) {
        Lep(j, i) {
            tmp = f[i] & f[j];
            if (tmp.count() == 2) {
                int u = tmp._Find_first(), v = tmp._Find_next(u);
                if (!g[u][v]) printf("%d %d\n", u, v);
                g[u].set(v), g[v].set(u);
                nlf[u] = nlf[v] = true;
            }
        }
    }
    int cnt = 0, rt;
    Rep(i, N) {
        if (nlf[i])
            vt[++cnt] = i, rt = i;
        else {
            int mn = 0;
            Rep(j, N) if (f[j][i] &&
                          (mn == 0 || f[mn].count() > f[j].count()) && !flg[j])
                mn = j;
            // printf("> %d %d\n", i, mn);
            t[i] = f[mn];
            flg[mn] = true;
        }
    }
    if (N == 50) printf("%d\n", N);
    if (cnt == 0) {
        rt = 1;
        Rep(i, N) if (i != rt) printf("%d %d\n", i, rt);
        return;
    } else if (cnt == 2) {
        int rt2;
        Rep(i, N) if (nlf[i] && i != rt) rt2 = i;
        Rep(i, N) if (!nlf[i]) {
            for (int j = t[i]._Find_first(); j != t[i].size();
                 j = t[i]._Find_next(j))
                if (!nlf[j]) {
                    printf("%d %d\n", j, rt);
                    nlf[j] = true;
                }
            std::swap(rt, rt2);
        }
        return;
    }
    Rep(i, cnt) g[vt[i]].set(vt[i]);
    Rep(i, N) if (!nlf[i]) {
        for (int j = t[i]._Find_first(); j != t[i].size();
             j = t[i]._Find_next(j))
            if (!nlf[j]) t[i][j] = 0;
        // printf("%d:\n", i);
        // print(t[i]);
        Rep(j, cnt) if ((g[vt[j]] & t[i]) == t[i]) {
            printf("%d %d\n", i, vt[j]);
            break;
        }
    }
}

int main() {
#ifndef ONLINE_JUDGE
    FIN("3.in");
    FOUT("1.out");
#endif
    read(N);
    if (N == 1) return 0;
    if (N == 2) return puts("1 2"), 0;
    int k;
    Rep(i, N) {
        read(k);
        while (k--) f[i].set(input<int>());
    }
    solve();
    return 0;
}