#include <bits/stdc++.h>
using namespace std;
const int MOD = (int)1e9 + 7;
const int INF = (int)1e9;
const long long LINF = (long long)1e18;
const long double PI = 2 * acos((long double)0);
long long gcd(long long a, long long b) {
  long long r;
  while (b != 0) {
    r = a % b;
    a = b;
    b = r;
  }
  return a;
}
long long lcm(long long a, long long b) { return a / gcd(a, b) * b; }
long long fpow(long long n, long long k, int p = MOD) {
  long long r = 1;
  for (; k; k >>= 1) {
    if (k & 1) r = r * n % p;
    n = n * n % p;
  }
  return r;
}
void addmod(int& a, int val, int p = MOD) {
  if ((a = (a + val)) >= p) a -= p;
}
void submod(int& a, int val, int p = MOD) {
  if ((a = (a - val)) < 0) a += p;
}
int mult(int a, int b, int p = MOD) { return (long long)a * b % p; }
int inv(int a, int p = MOD) { return fpow(a, p - 2, p); }
struct Dinic {
  int n, s, t, E, adj[1000010], flow[1000010], cap[1000010], next[1000010],
      last[1000010], run[1000010], level[1000010], que[1000010];
  void init(int _n, int _s, int _t) {
    n = _n;
    s = _s;
    t = _t;
    E = 0;
    for (int i = 0; i <= n; i++) last[i] = -1;
  }
  void add(int u, int v, int c1, int c2) {
    adj[E] = v;
    flow[E] = 0;
    cap[E] = c1;
    next[E] = last[u];
    last[u] = E++;
    adj[E] = u;
    flow[E] = 0;
    cap[E] = c2;
    next[E] = last[v];
    last[v] = E++;
  }
  bool bfs() {
    for (int i = 0; i <= n; i++) level[i] = -1;
    level[s] = 0;
    int qsize = 0;
    que[qsize++] = s;
    for (int i = 0; i < qsize; i++) {
      for (int u = que[i], e = last[u]; e != -1; e = next[e]) {
        int v = adj[e];
        if (flow[e] < cap[e] && level[v] == -1) {
          level[v] = level[u] + 1;
          que[qsize++] = v;
        }
      }
    }
    return level[t] != -1;
  }
  int dfs(int u, int bot) {
    if (u == t) return bot;
    for (int& e = run[u]; e != -1; e = next[e]) {
      int v = adj[e], delta = 0;
      if (level[v] == level[u] + 1 && flow[e] < cap[e] &&
          (delta = dfs(v, min(bot, cap[e] - flow[e]))) > 0) {
        flow[e] += delta;
        flow[e ^ 1] -= delta;
        return delta;
      }
    }
    return 0;
  }
  int maxflow() {
    int total = 0;
    while (bfs()) {
      for (int i = 0; i <= n; i++) run[i] = last[i];
      for (int delta = dfs(s, 1000000000); delta > 0;
           delta = dfs(s, 1000000000))
        total += delta;
    }
    return total;
  }
} dinic;
const int maxn = 200010;
int n, m;
int id[6][6];
int cnt[100];
int d[6];
int x[6];
int lst[6];
int com[maxn];
vector<int> his;
int dj[6];
void init() {
  for (int i = (0); i < (6); i++) dj[i] = i;
}
int find(int u) { return dj[u] == u ? dj[u] : dj[u] = find(dj[u]); }
void join(int u, int v) {
  int p = find(u);
  int q = find(v);
  dj[p] = q;
}
void rollback() {
  while (int((his).size())) {
    cnt[his.back()]++;
    his.pop_back();
  }
}
int check(int k) {
  init();
  for (int i = (0); i < (k); i++) {
    vector<int> vv;
    for (int j = (0); j < (k + 1); j++) {
      if ((((x[i]) >> (j)) & 1)) {
        vv.push_back(j);
      }
    }
    assert(int((vv).size()) == 2);
    if (!cnt[id[vv[0]][vv[1]]]) {
      rollback();
      return 0;
    }
    cnt[id[vv[0]][vv[1]]]--;
    his.push_back(id[vv[0]][vv[1]]);
    join(vv[0], vv[1]);
  }
  int ncom = 0;
  for (int i = (0); i < (k + 1); i++) {
    ncom += dj[i] == i;
  }
  if (ncom != 1) {
    rollback();
    return 0;
  }
  int tot = (k + 1) * (k + 2);
  int s = tot++, t = tot++;
  dinic.init(tot, s, t);
  for (int i = (0); i < (k + 1); i++)
    for (int j = (i); j < (k + 1); j++) {
      dinic.add(s, i * (k + 1) + j, cnt[id[i][j]], 0);
      dinic.add(i * (k + 1) + j, (k + 1) * (k + 1) + i, 1000000000, 0);
      dinic.add(i * (k + 1) + j, (k + 1) * (k + 1) + j, 1000000000, 0);
    }
  int sum = 0;
  for (int i = (0); i < (k + 1); i++) {
    dinic.add((k + 1) * (k + 1) + i, t, d[i] - 1, 0);
    sum += d[i] - 1;
  }
  rollback();
  return dinic.maxflow() == sum;
}
void go(int k) {
  if (k == m - 1) {
    if (check(k)) {
      for (int i = (0); i < (k); i++) {
        int tot = 0;
        for (int j = (0); j < (m); j++) {
          if ((((x[i]) >> (j)) & 1)) {
            cout << lst[j];
            if (++tot == 1) cout << " ";
          }
        }
        cout << "\n";
      }
      for (int i = (0); i < (m); i++)
        for (int j = (i); j < (m); j++) {
          int u = i * (k + 1) + j;
          for (int e = dinic.last[u]; ~e; e = dinic.next[e]) {
            int v = dinic.adj[e];
            for (int l = (0); l < (dinic.flow[e]); l++) {
              if ((k + 1) * (k + 1) + i != v) {
                cout << lst[i] << " " << lst[j] + 1 << "\n";
                lst[j]++;
              } else {
                cout << lst[j] << " " << lst[i] + 1 << "\n";
                lst[i]++;
              }
            }
          }
        }
      exit(0);
    }
    return;
  }
  for (int i = (0); i < (m); i++)
    for (int j = (i + 1); j < (m); j++) {
      x[k] = (1 << i) | (1 << j);
      go(k + 1);
    }
}
void solve() {
  for (int i = (0); i < (6); i++)
    for (int j = (0); j < (6); j++) {
      id[i][j] = 6 * i + j;
    }
  cin >> n;
  for (int i = (0); i < (n - 1); i++) {
    string s, t;
    cin >> s >> t;
    int u = int((s).size()) - 1, v = int((t).size()) - 1;
    if (u > v) swap(u, v);
    cnt[id[u][v]]++;
  }
  for (int i = (1); i < (n + 1); i++) {
    if (i < 10) {
      d[0]++;
      m = 1;
      com[i] = 0;
      lst[0] = 1;
    } else if (i < 100) {
      d[1]++;
      m = 2;
      com[i] = 1;
      lst[1] = 10;
    } else if (i < 1000) {
      d[2]++;
      m = 3;
      com[i] = 2;
      lst[2] = 100;
    } else if (i < 10000) {
      d[3]++;
      m = 4;
      com[i] = 3;
      lst[3] = 1000;
    } else if (i < 100000) {
      d[4]++;
      m = 5;
      com[i] = 4;
      lst[4] = 10000;
    } else if (i < 1000000) {
      d[5]++;
      m = 6;
      com[i] = 5;
      lst[5] = 100000;
    }
  }
  go(0);
  cout << -1;
}
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  solve();
  return 0;
}
