#include <bits/stdc++.h>
using namespace std;
inline int read() {
  int x = 0;
  bool t = false;
  char ch = getchar();
  while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
  if (ch == '-') t = true, ch = getchar();
  while (ch <= '9' && ch >= '0') x = x * 10 + ch - 48, ch = getchar();
  return t ? -x : x;
}
namespace Flow {
const int inf = 1e9;
struct Line {
  int v, next, w;
} e[1000];
int h[1000], cnt = 2;
inline void Add(int u, int v, int w) {
  e[cnt] = (Line){v, h[u], w};
  h[u] = cnt++;
  e[cnt] = (Line){u, h[v], 0};
  h[v] = cnt++;
}
int S, T, level[1000], cur[1000];
bool bfs() {
  for (int i = S; i <= T; ++i) level[i] = 0;
  queue<int> Q;
  Q.push(S);
  level[S] = 1;
  while (!Q.empty()) {
    int u = Q.front();
    Q.pop();
    for (int i = h[u]; i; i = e[i].next)
      if (!level[e[i].v] && e[i].w)
        level[e[i].v] = level[u] + 1, Q.push(e[i].v);
  }
  return level[T];
}
int dfs(int u, int flow) {
  if (u == T || !flow) return flow;
  int ret = 0;
  for (int &i = cur[u]; i; i = e[i].next) {
    int v = e[i].v, d;
    if (e[i].w && level[v] == level[u] + 1) {
      d = dfs(v, min(flow, e[i].w));
      ret += d;
      flow -= d;
      e[i].w -= d;
      e[i ^ 1].w += d;
      if (!flow) break;
    }
  }
  if (!ret) level[u] = 0;
  return ret;
}
int Dinic() {
  int ret = 0;
  while (bfs()) {
    for (int i = S; i <= T; ++i) cur[i] = h[i];
    ret += dfs(S, inf);
  }
  return ret;
}
void Clear() {
  for (int i = S; i <= T; ++i) h[i] = 0;
  cnt = 2;
}
}  // namespace Flow
using namespace Flow;
char ch[20];
int Read() {
  scanf("%s", ch);
  return strlen(ch);
}
int f[200200], n, Len[200200];
int getf(int x) { return x == f[x] ? x : f[x] = getf(f[x]); }
pair<int, int> E[10];
int key[10], g[10][10], num[10], pur[10];
void Output() {
  static int top[10];
  int m = Len[n];
  for (int i = 1; i < m; ++i)
    printf("%d %d\n", key[E[i].first], key[E[i].second]);
  for (int i = 1; i <= m; ++i) top[i] = key[i];
  int now = m;
  for (int i = 1; i <= m; ++i)
    for (int j = i; j <= m; ++j) {
      ++now;
      for (int k = h[now]; k; k = e[k].next) {
        int v = e[k].v;
        if (v == S) continue;
        int p = e[k ^ 1].w;
        while (p--) printf("%d %d\n", key[i ^ j ^ v], ++top[v]);
      }
    }
  exit(0);
}
void check() {
  bool fl = true;
  int m = Len[n];
  if (m >= 2) {
    static int dg[10];
    for (int i = 1; i <= m; ++i) dg[i] = 1;
    for (int i = 1; i <= m - 2; ++i) dg[pur[i]] += 1;
    for (int i = 1; i <= m - 2; ++i) {
      int p = 0;
      for (int j = 1; j <= m; ++j)
        if (dg[j] == 1) {
          p = j;
          break;
        }
      E[i] = make_pair(pur[i], p);
      --dg[p];
      --dg[pur[i]];
    }
    E[m - 1] = make_pair(0, 0);
    for (int i = 1; i <= m; ++i)
      if (dg[i] == 1) E[m - 1].first ? E[m - 1].second = i : E[m - 1].first = i;
    for (int i = 1; i < m; ++i)
      if (E[i].first > E[i].second) swap(E[i].first, E[i].second);
    for (int i = 1; i < m; ++i)
      if (--g[E[i].first][E[i].second] < 0) fl = false;
  }
  if (fl) {
    Flow::Clear();
    S = 0;
    int now = m;
    for (int i = 1; i <= m; ++i)
      for (int j = i; j <= m; ++j)
        ++now, Add(S, now, g[i][j]), Add(now, i, inf), Add(now, j, inf);
    T = now + 1;
    for (int i = 1; i <= m; ++i) Add(i, T, num[i] - 1);
    if (Dinic() == n - m) Output();
  }
  for (int i = 1; i < m; ++i) ++g[E[i].first][E[i].second];
}
void dfs(int x) {
  if (x >= Len[n] - 1) {
    check();
    return;
  }
  for (int i = 1; i <= Len[n]; ++i) pur[x] = i, dfs(x + 1);
}
int main() {
  n = read();
  for (int i = 1; i <= n; ++i) Len[i] = Len[i / 10] + 1, num[Len[i]] += 1;
  for (int i = 1; i <= n; ++i)
    if (Len[i] ^ Len[i - 1]) key[Len[i]] = i;
  for (int i = 1, x, y; i < n; ++i)
    x = Read(), y = Read(), g[min(x, y)][max(x, y)] += 1;
  dfs(1);
  puts("-1");
  return 0;
}
