#include <bits/stdc++.h>
using namespace std;
template <typename T1, typename T2>
void chkmin(T1 &x, T2 y) {
  if (x > y) x = y;
}
template <typename T1, typename T2>
void chkmax(T1 &x, T2 y) {
  if (x < y) x = y;
}
inline void debug(int x) { fprintf(stderr, "ycx has aked ioi %d times\n", x); }
namespace fastio {
char rbuf[1 << 23], *p1 = rbuf, *p2 = rbuf, wbuf[1 << 23], *p3 = wbuf;
inline char getc() {
  return p1 == p2 &&
                 (p2 = (p1 = rbuf) + fread(rbuf, 1, 1 << 23, stdin), p1 == p2)
             ? -1
             : *p1++;
}
inline void putc(char x) { (*p3++ = x); }
template <typename T>
void read(T &x) {
  x = 0;
  char c = getchar();
  T neg = 0;
  while (!isdigit(c)) neg |= !(c ^ '-'), c = getchar();
  while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
  if (neg) x = (~x) + 1;
}
template <typename T>
void recursive_print(T x) {
  if (!x) return;
  recursive_print(x / 10);
  putc(x % 10 ^ 48);
}
template <typename T>
void print(T x) {
  if (!x) putc('0');
  if (x < 0) putc('-'), x = ~x + 1;
  recursive_print(x);
}
template <typename T>
void print(T x, char c) {
  if (!x) putc('0');
  if (x < 0) putc('-'), x = ~x + 1;
  recursive_print(x);
  putc(c);
}
void print_final() { fwrite(wbuf, 1, p3 - wbuf, stdout); }
}  // namespace fastio
const int MAXV = 30;
const int MAXE = 300 * 2;
const int INF = 0x3f3f3f3f;
int n, m, p[8], q[8], cnt[8];
int S = 29, T = 30, hd[MAXV + 5], to[MAXE + 5], nxt[MAXE + 5], cap[MAXE + 5],
    ec = 1;
void init() {
  memset(hd, 0, sizeof(hd));
  ec = 1;
}
void adde(int u, int v, int f) {
  to[++ec] = v;
  cap[ec] = f;
  nxt[ec] = hd[u];
  hd[u] = ec;
  to[++ec] = u;
  cap[ec] = 0;
  nxt[ec] = hd[v];
  hd[v] = ec;
}
int dep[MAXV + 5], now[MAXV + 5];
bool getdep() {
  memset(dep, -1, sizeof(dep));
  dep[S] = 0;
  queue<int> q;
  q.push(S);
  now[S] = hd[S];
  while (!q.empty()) {
    int x = q.front();
    q.pop();
    for (int e = hd[x]; e; e = nxt[e]) {
      int y = to[e], z = cap[e];
      if (!~dep[y] && z) {
        dep[y] = dep[x] + 1;
        q.push(y);
        now[y] = hd[y];
      }
    }
  }
  return ~dep[T];
}
int getflow(int x, int f) {
  if (x == T) return f;
  int ret = 0;
  for (int &e = now[x]; e; e = nxt[e]) {
    int y = to[e], z = cap[e];
    if (dep[y] == dep[x] + 1 && z) {
      int w = getflow(y, min(f - ret, z));
      cap[e] -= w;
      cap[e ^ 1] += w;
      ret += w;
      if (ret == f) return ret;
    }
  }
  return ret;
}
int dinic() {
  int ret = 0;
  while (getdep()) ret += getflow(S, INF);
  return ret;
}
int num[8][8], cc[8][8], pru[8], deg[8], vis[8];
void solve() {
  memset(deg, 0, sizeof(deg));
  memset(vis, 0, sizeof(vis));
  memset(cc, 0, sizeof(cc));
  for (int i = 1; i <= m - 2; i++) deg[pru[i]]++;
  for (int i = 1; i <= m - 2; i++) {
    int pos = 0;
    for (int j = 1; j <= m; j++) {
      if (!deg[j] && !vis[j]) {
        pos = j;
        break;
      }
    }
    cc[min(pos, pru[i])][max(pos, pru[i])]++;
    deg[pru[i]]--;
    vis[pos] = 1;
  }
  int u1 = 1, u2 = m;
  while (vis[u1]) u1++;
  while (vis[u2]) u2--;
  cc[u1][u2]++;
  int cur = 0;
  init();
  for (int i = 1; i <= m; i++)
    for (int j = i; j <= m; j++) {
      if (cc[i][j] > num[i][j]) return;
      cur++;
      adde(S, cur, num[i][j] - cc[i][j]);
      adde(cur, m * (m + 1) / 2 + i, INF);
      adde(cur, m * (m + 1) / 2 + j, INF);
    }
  for (int i = 1; i <= m; i++) adde(m * (m + 1) / 2 + i, T, cnt[i] - 1);
  if (dinic() == n - m) {
    for (int i = 1; i <= m; i++)
      for (int j = i; j <= m; j++) {
        if (cc[i][j]) printf("%d %d\n", p[i], p[j]);
      }
    for (int i = 1; i <= m; i++) q[i] = p[i];
    cur = 0;
    for (int i = 1; i <= m; i++)
      for (int j = i; j <= m; j++) {
        cur++;
        for (int e = hd[cur]; e; e = nxt[e]) {
          int y = to[e], z = cap[e ^ 1];
          if (y == S) continue;
          if (y - m * (m + 1) / 2 == i) {
            while (z--) printf("%d %d\n", ++q[i], p[j]);
          } else {
            while (z--) printf("%d %d\n", ++q[j], p[i]);
          }
        }
      }
    exit(0);
  }
}
void dfs(int x) {
  if (x == m - 1) return solve();
  for (int i = 1; i <= m; i++) pru[x] = i, dfs(x + 1);
}
int main() {
  scanf("%d", &n);
  for (int cur = 1; cur <= n; cur *= 10) p[++m] = cur;
  for (int i = 1; i < m; i++) cnt[i] = p[i + 1] - p[i];
  cnt[m] = n - p[m] + 1;
  for (int i = 1; i < n; i++) {
    static char s1[9], s2[9];
    scanf("%s%s", s1 + 1, s2 + 1);
    int l1 = strlen(s1 + 1), l2 = strlen(s2 + 1);
    if (l1 > l2) l1 ^= l2 ^= l1 ^= l2;
    num[l1][l2]++;
  }
  if (m == 1) {
    if (num[1][1] != n - 1) return puts("-1"), 0;
    for (int i = 1; i < n; i++) printf("%d %d\n", i, i + 1);
    return 0;
  }
  dfs(1);
  puts("-1");
  return 0;
}
