#include <bits/stdc++.h>
using namespace std;
struct edge {
  int t, nxt, f;
} e[3000010];
int n, ln, u, v, be[200050], cnt, ed[10][10], t[10][10], id[10], lg[200010],
    p[10], pn[10], S, T, tmp, pu[10], pv[10], dep[200050], nw[200050], td,
    tt[10][10], hv[10], te[10];
char tu[10], tv[10];
queue<int> q;
void add(const int& x, const int& y, const int& f) {
  e[++cnt] = (edge){y, be[x], f}, be[x] = cnt;
}
bool bfs() {
  for (int i = S; i <= T; ++i) dep[i] = 0;
  dep[S] = 1, q.push(S);
  while (!q.empty()) {
    td = q.front(), q.pop();
    for (int i = be[td]; i; i = e[i].nxt)
      if (e[i].f && !dep[e[i].t]) q.push(e[i].t), dep[e[i].t] = dep[td] + 1;
  }
  return dep[T];
}
int dfs(const int& x, const int& f) {
  int nf = 0, tf;
  if (x == T) return f;
  for (int i = nw[x]; i && nf < f; nw[x] = i, i = e[i].nxt)
    if (e[i].f && dep[e[i].t] == dep[x] + 1)
      tf = dfs(e[i].t, min(f - nf, e[i].f)), nf += tf, e[i].f -= tf,
      e[(i & 1 ? i + 1 : i - 1)].f += tf;
  return nf;
}
void Calc() {
  cnt = tmp = 0;
  for (int i = S; i <= T; ++i) be[i] = 0;
  for (int i = 1; i <= n; ++i)
    if (id[lg[i]] != i) (add(S, i, 1), add(i, S, 0));
  for (int i = 1; i <= n; ++i)
    if (id[lg[i]] != i)
      for (int j = 1; j <= ln; ++j)
        (add(i,
             (lg[i] < j ? n + (lg[i] - 1) * ln + j : n + (j - 1) * ln + lg[i]),
             1),
         add((lg[i] < j ? n + (lg[i] - 1) * ln + j : n + (j - 1) * ln + lg[i]),
             i, 0));
  for (int i = 1; i <= ln; ++i)
    for (int j = i; j <= ln; ++j)
      (add((i < j ? n + (i - 1) * ln + j : n + (j - 1) * ln + i), T, t[i][j]),
       add(T, (i < j ? n + (i - 1) * ln + j : n + (j - 1) * ln + i), 0));
  while (bfs()) {
    for (int i = S; i <= T; ++i) nw[i] = be[i];
    tmp += dfs(S, 1e9);
  }
  if (tmp == n - ln) {
    for (int i = 1; i < ln; ++i)
      printf("%d %d\n", id[pu[i]], id[pv[i]]),
          tt[pu[i]][pv[i]] = (++tt[pv[i]][pu[i]]);
    for (int i = 1; i <= n; ++i)
      if (id[lg[i]] != i)
        for (int j = be[i]; j; j = e[j].nxt)
          if (e[j].t && !e[j].f) {
            if ((e[j].t - n - 1) % ln + 1 == lg[i])
              printf("%d %d\n", i, id[(e[j].t - n - 1) / ln + 1]),
                  tt[lg[i]][(e[j].t - n - 1) / ln + 1] =
                      (++tt[(e[j].t - n - 1) / ln + 1][lg[i]]);
            else
              printf("%d %d\n", i, id[(e[j].t - n - 1) % ln + 1]),
                  tt[lg[i]][(e[j].t - n - 1) % ln + 1] =
                      (++tt[(e[j].t - n - 1) % ln + 1][lg[i]]);
            break;
          }
    for (int i = 1; i <= ln; ++i)
      for (int j = 1; j <= ln; ++j) assert(ed[i][j] == tt[i][j]);
    exit(0);
  }
}
void dfs(const int& x) {
  if (x > ln - 2) {
    for (int i = 1; i <= ln; ++i)
      for (int j = 1; j <= ln; ++j) t[i][j] = ed[i][j];
    for (int i = 1; i <= ln; ++i) pn[i] = 0;
    for (int i = 1; i <= ln - 2; ++i) ++pn[p[i]];
    tmp = 0;
    for (int i = 1; i <= ln - 2; ++i) {
      for (int j = 1; j <= ln; ++j)
        if (!pn[j]) {
          t[p[i]][j] = (--t[j][p[i]]), pu[++tmp] = p[i], pv[tmp] = j,
          pn[j] = -1;
          if (t[p[i]][j] < 0) return;
          break;
        }
      --pn[p[i]];
    }
    tmp = 0;
    for (int i = 1; i <= ln; ++i)
      if (!pn[i]) {
        if (tmp) {
          t[i][tmp] = (--t[tmp][i]), pu[ln - 1] = i, pv[ln - 1] = tmp;
          if (t[i][tmp] < 0) return;
        } else
          tmp = i;
      }
    return Calc();
  }
  for (int i = 1; i <= ln; ++i) p[x] = i, dfs(x + 1);
}
int main() {
  scanf("%d", &n);
  for (int i = 1; i <= n; ++i) lg[i] = lg[i / 10] + 1;
  ln = lg[n], T = n + ln * ln + 1;
  for (int i = 1, j = 1; i <= ln; ++i, j *= 10) id[i] = j;
  for (int i = 1; i < n; ++i)
    scanf("%s%s", tu, tv), u = strlen(tu), v = strlen(tv), ++hv[u], ++hv[v],
                           u == v ? ++te[u] : 0, ed[u][v] = (++ed[v][u]);
  if (n >= 10)
    for (int i = 1, j = 9, ls = 0; i <= ln;
         ++i, ls += j, ls + j * 10 > n ? j = n - ls : j *= 10)
      if (hv[i] < j || te[i] > j - 1) return puts("-1"), 0;
  dfs(1);
  return puts("-1"), 0;
}
