#include <bits/stdc++.h>
using namespace std;
const int maxn = 200010;
int l[maxn], e = 0, _;
stack<int> sta[10];
char buf1[10], buf2[10];
int n, c, fa[maxn];
int edge_cnt[10][10], _cnt[10][10];
vector<pair<int, int> > edge;
int getroot(int x) {
  if (x == fa[x]) return x;
  return getroot(fa[x]);
}
int getc(int x) {
  int ret = 0;
  while (x) {
    ++ret;
    x /= 10;
  }
  return ret;
}
int col[maxn], ind[maxn], tot;
namespace netflow {
int l[112], L[112], Q[112], e;
struct Edge {
  int v, c, x;
} E[100010];
inline void addEdge(int u, int v, int c) {
  E[e].v = v, E[e].x = l[u], E[e].c = c, l[u] = e++;
  E[e].v = u, E[e].x = l[v], E[e].c = 0, l[v] = e++;
}
int _bfs() {
  for (int i = 1; i <= 2 + c + c * c; i++) L[i] = -1;
  int s = 0, t = 0, u;
  Q[t++] = 1, L[1] = 0;
  while (s < t) {
    u = Q[s++];
    for (int p = l[u]; p >= 0; p = E[p].x) {
      if (L[E[p].v] == -1 && E[p].c) {
        L[Q[t++] = E[p].v] = L[u] + 1;
      }
    }
  }
  return L[2] != -1;
}
int _find(int u, int in) {
  if (u == 2) return in;
  int w = 0, t;
  for (int p = l[u]; p >= 0 && w < in; p = E[p].x) {
    if (E[p].c && L[E[p].v] == L[u] + 1) {
      if ((t = _find(E[p].v, min(E[p].c, in - w)))) {
        E[p].c -= t, E[p ^ 1].c += t;
        w += t;
      }
    }
  }
  if (w < in) L[u] = -1;
  return w;
}
int dinic() {
  int res = 0, t;
  while (_bfs()) {
    while ((t = _find(1, 0x3f3f3f3f))) {
      res += t;
    }
  }
  return res;
}
void init() {
  e = 0;
  for (int i = 1; i <= 2 + c + c * c; i++) l[i] = -1;
}
int findpath() {
  int S, T;
  int u = 1, f = 0;
  for (int p = l[u]; p >= 0; p = E[p].x) {
    if (!(p & 1) && E[p ^ 1].c) {
      f = E[p].v;
      --E[p ^ 1].c;
      break;
    }
  }
  if (!f) return 0;
  S = u = f;
  for (int p = l[u]; p >= 0; p = E[p].x) {
    if (!(p & 1) && E[p ^ 1].c) {
      --E[p ^ 1].c;
      u = E[p].v;
      break;
    }
  }
  T = u;
  for (int p = l[u]; p >= 0; p = E[p].x) {
    if (!(p & 1) && E[p ^ 1].c) {
      --E[p ^ 1].c;
      u = E[p].v;
      break;
    }
  }
  int x = (T - 2 - c - 1) / c + 1, y = (T - 2 - c - 1) % c + 1;
  ++tot;
  col[tot] = S - 2;
  if (x == S - 2)
    edge.push_back(pair<int, int>(tot, y));
  else
    edge.push_back(pair<int, int>(tot, x));
  return 1;
}
void solve() {
  int sum = 0;
  for (int i = 1; i <= c; i++) {
    sum += int(sta[i].size() - 1);
    addEdge(1, 2 + i, int(sta[i].size() - 1));
    for (int j = 1; j <= c; j++) {
      int x = i, y = j;
      if (x > y) swap(x, y);
      addEdge(2 + i, 2 + c + (x - 1) * c + y, 0x3f3f3f3f);
    }
  }
  for (int i = 1; i <= c; i++) {
    for (int j = i; j <= c; j++) {
      addEdge(2 + c + (i - 1) * c + j, 2, _cnt[i][j]);
    }
  }
  if (dinic() == sum) {
    tot = c;
    for (int i = 1; i <= c; i++) col[i] = i;
    while (findpath())
      ;
    for (int i = 1; i <= n; i++) {
      ind[i] = sta[col[i]].top();
      sta[col[i]].pop();
    }
    for (int i = 0; i < edge.size(); i++) {
      int u = edge[i].first, v = edge[i].second;
      printf("%d %d\n", ind[u], ind[v]);
    }
    exit(0);
  }
}
}  // namespace netflow
void dfs(int u, int v) {
  if (u > c || v >= u) {
    if (u > c) {
      if (_ == 1) {
        int ok = 1;
        for (int i = 1; i <= c; i++) {
          for (int j = i; j <= c; j++) {
            _cnt[i][j] = edge_cnt[i][j];
          }
        }
        for (int i = 0; i < edge.size(); i++)
          --_cnt[edge[i].second][edge[i].first];
        for (int i = 1; i <= c; i++) {
          for (int j = i; j <= c; j++) {
            if (_cnt[i][j] < 0) {
              ok = 0;
            }
          }
        }
        if (ok) {
          netflow::init();
          netflow::solve();
        }
      }
      return;
    } else {
      dfs(u + 1, 1);
    }
  } else {
    int ru = getroot(u), rv = getroot(v);
    if (ru != rv) {
      --_;
      edge.push_back(pair<int, int>(u, v));
      fa[ru] = rv;
      dfs(u, v + 1);
      fa[ru] = ru;
      edge.pop_back();
      ++_;
    }
    dfs(u, v + 1);
  }
}
int main() {
  scanf("%d", &n);
  for (int i = 1; i < n; i++) {
    scanf("%s%s", buf1, buf2);
    int x = int(strlen(buf1)), y = int(strlen(buf2));
    if (x > y) swap(x, y);
    edge_cnt[x][y]++;
  }
  c = getc(n);
  _ = c;
  for (int i = 1; i <= c; i++) fa[i] = i;
  for (int i = 1; i <= n; i++) sta[getc(i)].push(i);
  dfs(2, 1);
  puts("-1");
  return 0;
}
