#include <bits/stdc++.h>
using namespace std;
const int inf = 1e7;
int n, m, pru[9], sm[9], f[9][9], t[9], num[9];
int head[1000], cur[1000], dep[1000], cnt, S, T, nod;
set<int> s;
queue<int> Q;
struct Edge {
  int fr, to;
} E[10];
struct edge {
  int next, to, w;
} a[1000];
void link(int x, int y, int w) {
  a[++cnt] = (edge){head[x], y, w};
  head[x] = cnt;
  a[++cnt] = (edge){head[y], x, 0};
  head[y] = cnt;
}
int BFS() {
  memset(dep, 0, sizeof(dep));
  dep[S] = 1;
  Q.push(S);
  while (!Q.empty()) {
    int x = Q.front();
    Q.pop();
    for (int i = head[x]; i; i = a[i].next)
      if (!dep[a[i].to] && a[i].w) dep[a[i].to] = dep[x] + 1, Q.push(a[i].to);
  }
  return dep[T];
}
int DFS(int x, int flow) {
  if (x == T) return flow;
  for (int &i = cur[x]; i; i = a[i].next) {
    int R = a[i].to;
    if (!a[i].w || dep[R] != dep[x] + 1) continue;
    int k = DFS(R, min(flow, a[i].w));
    if (k) {
      a[i].w -= k, a[i ^ 1].w += k;
      return k;
    }
  }
  return 0;
}
int Dinic() {
  int res = 0;
  while (BFS()) {
    for (int i = 1; i <= nod; i++) cur[i] = head[i];
    while (int tmp = DFS(S, inf)) res += tmp;
  }
  return res;
}
void Print() {
  queue<int> Q[9];
  for (int i = 1; i <= m; i++)
    while (!Q[i].empty()) Q[i].pop();
  for (int i = 1, fl = 0; i <= n; i++, fl = 0) {
    for (int j = m; j >= 1; j--)
      if (i == sm[j]) fl = 1;
    for (int j = m; j >= 1 && !fl; j--)
      if (i > sm[j]) Q[j].push(i), fl = 1;
  }
  for (int i = 1; i < m; i++) printf("%d %d\n", sm[E[i].fr], sm[E[i].to]);
  nod = m + 2;
  for (int p1 = 1; p1 <= m; p1++)
    for (int p2 = p1; p2 <= m; p2++) {
      ++nod;
      for (int i = head[nod]; i; i = a[i].next)
        if (a[i].to >= 3 && a[i].to <= m + 2) {
          int to = a[i].to - 2, fr = p1 + p2 - to;
          for (int w = 1; w <= a[i ^ 1].w; w++)
            printf("%d %d\n", sm[fr], Q[to].front()), Q[to].pop();
        }
    }
  exit(0);
}
void Check() {
  int flag = 1;
  if (m >= 2) {
    for (int i = 1; i <= m; i++) t[i] = 0;
    for (int i = 1; i <= m - 2; i++) t[pru[i]]++;
    s.clear();
    for (int i = 1; i <= m; i++)
      if (!t[i]) s.insert(i);
    for (int i = 1; i <= m - 2; i++) {
      E[i] = (Edge){pru[i], *s.begin()};
      s.erase(s.begin());
      if (--t[pru[i]] == 0) s.insert(pru[i]);
    }
    E[m - 1] = (Edge){*s.begin(), *s.rbegin()};
    for (int i = 1; i < m; i++)
      if (E[i].fr > E[i].to) swap(E[i].fr, E[i].to);
    for (int i = 1; i < m; i++)
      if (--f[E[i].fr][E[i].to] < 0) flag = 0;
  }
  if (flag) {
    memset(head, 0, sizeof(head));
    cnt = 1;
    S = 1;
    T = 2;
    nod = m + 2;
    for (int i = 1; i <= m; i++)
      for (int j = i; j <= m; j++) {
        ++nod;
        link(S, nod, f[i][j]);
        link(nod, i + 2, inf);
        link(nod, j + 2, inf);
      }
    for (int i = 1; i <= m; i++) link(i + 2, T, num[i]);
    if (Dinic() == n - m) Print();
  }
  for (int i = 1; i < m; i++) f[E[i].fr][E[i].to]++;
}
void dfs(int i) {
  if (i >= m - 1) {
    Check();
    return;
  }
  for (int x = 1; x <= m; x++) pru[i] = x, dfs(i + 1);
}
int main() {
  cin >> n;
  sm[1] = 1;
  for (int x = n; x; x /= 10) m++;
  for (int i = 2; i <= m; i++)
    sm[i] = 10 * sm[i - 1], num[i - 1] = sm[i] - sm[i - 1] - 1;
  num[m] = n - sm[m];
  for (int i = 1; i < n; i++) {
    char s1[10], s2[10];
    int l1, l2;
    scanf("%s%s", s1 + 1, s2 + 1);
    l1 = strlen(s1 + 1);
    l2 = strlen(s2 + 1);
    if (l1 > l2) swap(l1, l2);
    f[l1][l2]++;
  }
  dfs(1);
  puts("-1");
}
