#include <bits/stdc++.h>
using namespace std;
template <class T>
T sqr(T x) {
  return x * x;
}
const int maxn = 600001;
struct edges {
  int v, flow, rev, full;
} mm;
vector<edges> c[maxn];
int d[maxn];
int edge[21][21];
char str[21];
int st, en;
pair<int, int> sf[4000];
vector<pair<int, int> > fin;
const int inf = 1e9;
int vis[21];
inline bool build() {
  queue<int> q;
  memset(d, 0, sizeof(d));
  d[st] = 1;
  q.push(st);
  while (!q.empty()) {
    int x = q.front();
    q.pop();
    if (c[x].size())
      for (int i = 0; i <= c[x].size() - 1; i++)
        if (c[x][i].flow && !d[c[x][i].v]) {
          d[c[x][i].v] = d[x] + 1;
          if (c[x][i].v == en) return true;
          q.push(c[x][i].v);
        }
  }
  return false;
}
int dinic(int k, int fw) {
  int flow, i, f = 0;
  if (k == en) return fw;
  for (int i = 0; i <= c[k].size() - 1; i++)
    if (d[c[k][i].v] == d[k] + 1 && c[k][i].flow) {
      flow = dinic(c[k][i].v, min(fw, c[k][i].flow));
      fw -= flow;
      f += flow;
      c[k][i].flow -= flow;
      c[c[k][i].v][c[k][i].rev].flow += flow;
    }
  if (!f) d[k] = -1;
  return f;
}
int val[] = {0, 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000};
int now[21], cnt[21];
int n, m;
void dfs(int k) {
  for (int i = 1; i <= m; i++)
    if (!vis[i] && (edge[k][i] + edge[i][k])) {
      vis[i] = 1;
      if (k > i)
        edge[i][k]--;
      else
        edge[k][i]--;
      fin.push_back(pair<int, int>(val[k], val[i]));
      dfs(i);
    }
}
inline void addedge(int x, int y, int s) {
  int v1, v2;
  v1 = c[x].size();
  v2 = c[y].size();
  mm.v = y;
  mm.flow = s;
  mm.rev = v2;
  mm.full = s;
  c[x].push_back(mm);
  mm.v = x;
  mm.flow = 0;
  mm.rev = v1;
  mm.full = 0;
  c[y].push_back(mm);
}
int main() {
  for (int i = 1; i <= 7; i++) now[i] = val[i] + 1;
  scanf("%d", &n);
  for (int i = 1; i <= n - 1; i++) {
    scanf("%s", str);
    int sa = strlen(str);
    scanf("%s", str);
    int sb = strlen(str);
    m = max(m, max(sa, sb));
    if (sa > sb) swap(sa, sb);
    edge[sa][sb]++;
  }
  int xx = 1;
  for (int i = 1; i <= m; i++) {
    cnt[i] = (i == m) ? (n - val[xx] + 1) : (val[xx + 1] - val[xx]);
    xx++;
  }
  vis[1] = 1;
  dfs(1);
  for (int i = 1; i <= m; i++)
    if (!vis[i]) {
      puts("-1");
      return 0;
    }
  st = 0;
  en = m + (m * m + m) / 2 + 1;
  int tot = 0;
  for (int a = 1; a <= m; a++)
    for (int b = a; b <= m; b++) {
      tot++;
      sf[tot] = pair<int, int>(a, b);
      if (edge[a][b]) {
        addedge(m + tot, en, edge[a][b]);
        addedge(a, m + tot, edge[a][b]);
        if (a != b) addedge(b, m + tot, edge[a][b]);
      }
    }
  for (int i = 1; i <= m; i++) addedge(st, i, cnt[i] - 1);
  long long ans = 0;
  while (build()) ans += dinic(st, inf);
  if (ans != n - m) {
    puts("-1");
    return 0;
  }
  for (int i = 1; i <= m; i++) {
    for (auto u : c[i])
      if (u.full > u.flow && u.v > m && u.v < en) {
        int a = sf[u.v - m].first + sf[u.v - m].second;
        int b = a - i;
        a = a - b;
        for (int j = u.flow + 1; j <= u.full; j++)
          fin.push_back(pair<int, int>(now[a]++, val[b]));
      }
  }
  for (int i = 1; i <= 6; i++)
    if (now[i] > val[i + 1]) {
      puts("-1");
      return 0;
    }
  for (auto u : fin) printf("%d %d\n", u.first, u.second);
}
