#include <bits/stdc++.h>
template <typename T>
inline T max(T a, T b) {
  return a > b ? a : b;
}
template <typename T>
inline T min(T a, T b) {
  return a < b ? a : b;
}
template <typename T>
inline T abs(T a) {
  return a > 0 ? a : -a;
}
template <typename T>
inline bool repr(T &a, T b) {
  return a < b ? a = b, 1 : 0;
}
template <typename T>
inline bool repl(T &a, T b) {
  return a > b ? a = b, 1 : 0;
}
template <typename T>
inline T gcd(T a, T b) {
  T t;
  if (a < b) {
    while (a) {
      t = a;
      a = b % a;
      b = t;
    }
    return b;
  } else {
    while (b) {
      t = b;
      b = a % b;
      a = t;
    }
    return a;
  }
}
template <typename T>
inline T sqr(T x) {
  return x * x;
}
struct Cg {
  inline char operator()() { return getchar(); }
};
struct Cp {
  inline void operator()(char x) { putchar(x); }
};
inline bool IS(char x) { return x == 10 || x == 13 || x == ' '; }
template <typename T>
struct Fr {
  T P;
  inline Fr &operator,(int &x) {
    x = 0;
    char t = P();
    while ((t < '0' || t > '9') && t != '-') t = P();
    bool f = 0;
    if (t == '-') t = P(), f = 1;
    x = t - '0';
    for (t = P(); t >= '0' && t <= '9'; t = P()) x = x * 10 + t - '0';
    if (f) x = -x;
    return *this;
  }
  inline operator int() {
    int x;
    *this, x;
    return x;
  }
  inline Fr &operator,(long long &x) {
    x = 0;
    char t = P();
    while ((t < '0' || t > '9') && t != '-') t = P();
    bool f = 0;
    if (t == '-') t = P(), f = 1;
    x = t - '0';
    for (t = P(); t >= '0' && t <= '9'; t = P()) x = x * 10 + t - '0';
    if (f) x = -x;
    return *this;
  }
  inline operator long long() {
    long long x;
    *this, x;
    return x;
  }
  inline Fr &operator,(char &x) {
    for (x = P(); IS(x); x = P())
      ;
    return *this;
  }
  inline operator char() {
    char x;
    *this, x;
    return x;
  }
  inline Fr &operator,(char *x) {
    char t = P();
    for (; IS(t); t = P())
      ;
    if (~t) {
      for (; !IS(t) && ~t; t = P()) *x++ = t;
    }
    *x++ = 0;
    return *this;
  }
  inline Fr &operator,(double &x) {
    x = 0;
    char t = P();
    while ((t < '0' || t > '9') && t != '-') t = P();
    bool f = 0;
    if (t == '-') t = P(), f = 1;
    x = t - '0';
    for (t = P(); t >= '0' && t <= '9'; t = P()) x = x * 10 + t - '0';
    if (t == '.') {
      double u = 0.1;
      for (t = P(); t >= '0' && t <= '9'; t = P(), u *= 0.1) x += u * (t - '0');
    }
    if (f) x = -x;
    return *this;
  }
  inline operator double() {
    double x;
    *this, x;
    return x;
  }
  inline Fr &operator,(long double &x) {
    x = 0;
    char t = P();
    while ((t < '0' || t > '9') && t != '-') t = P();
    bool f = 0;
    if (t == '-') t = P(), f = 1;
    x = t - '0';
    for (t = P(); t >= '0' && t <= '9'; t = P()) x = x * 10 + t - '0';
    if (t == '.') {
      double u = 0.1;
      for (t = P(); t >= '0' && t <= '9'; t = P(), u *= 0.1) x += u * (t - '0');
    }
    if (f) x = -x;
    return *this;
  }
  inline operator long double() {
    long double x;
    *this, x;
    return x;
  }
  inline Fr &operator,(unsigned int &x) {
    x = 0;
    char t = P();
    while (t < '0' || t > '9') t = P();
    x = t - '0';
    for (t = P(); t >= '0' && t <= '9'; t = P()) x = x * 10 + t - '0';
    return *this;
  }
  inline operator unsigned int() {
    unsigned int x;
    *this, x;
    return x;
  }
  inline Fr &operator,(unsigned long long &x) {
    x = 0;
    char t = P();
    while (t < '0' || t > '9') t = P();
    x = t - '0';
    for (t = P(); t >= '0' && t <= '9'; t = P()) x = x * 10 + t - '0';
    return *this;
  }
  inline operator unsigned long long() {
    unsigned long long x;
    *this, x;
    return x;
  }
};
Fr<Cg> in;
template <typename T>
struct Fw {
  T P;
  inline Fw &operator,(int x) {
    if (x) {
      if (x < 0) P('-'), x = -x;
      char s[10], c = 0;
      while (x) s[c++] = x % 10 + '0', x /= 10;
      while (c--) P(s[c]);
    } else
      P('0');
    return *this;
  }
  inline Fw &operator()(int x) {
    if (x) {
      if (x < 0) P('-'), x = -x;
      char s[10], c = 0;
      while (x) s[c++] = x % 10 + '0', x /= 10;
      while (c--) P(s[c]);
    } else
      P('0');
    return *this;
  }
  inline Fw &operator,(unsigned int x) {
    if (x) {
      char s[10], c = 0;
      while (x) s[c++] = x % 10 + '0', x /= 10;
      while (c--) P(s[c]);
    } else
      P('0');
    return *this;
  }
  inline Fw &operator()(unsigned int x) {
    if (x) {
      char s[10], c = 0;
      while (x) s[c++] = x % 10 + '0', x /= 10;
      while (c--) P(s[c]);
    } else
      P('0');
    return *this;
  }
  inline Fw &operator,(long long x) {
    if (x) {
      if (x < 0) P('-'), x = -x;
      char s[19], c = 0;
      while (x) s[c++] = x % 10 + '0', x /= 10;
      while (c--) P(s[c]);
    } else
      P('0');
    return *this;
  }
  inline Fw &operator()(long long x) {
    if (x) {
      if (x < 0) P('-'), x = -x;
      char s[19], c = 0;
      while (x) s[c++] = x % 10 + '0', x /= 10;
      while (c--) P(s[c]);
    } else
      P('0');
    return *this;
  }
  inline Fw &operator,(unsigned long long x) {
    if (x) {
      char s[20], c = 0;
      while (x) s[c++] = x % 10 + '0', x /= 10;
      while (c--) P(s[c]);
    } else
      P('0');
    return *this;
  }
  inline Fw &operator()(unsigned long long x) {
    if (x) {
      char s[20], c = 0;
      while (x) s[c++] = x % 10 + '0', x /= 10;
      while (c--) P(s[c]);
    } else
      P('0');
    return *this;
  }
  inline Fw &operator,(char x) {
    P(x);
    return *this;
  }
  inline Fw &operator()(char x) {
    P(x);
    return *this;
  }
  inline Fw &operator,(const char *x) {
    while (*x) P(*x++);
    return *this;
  }
  inline Fw &operator()(const char *x) {
    while (*x) P(*x++);
    return *this;
  }
  inline Fw &operator()(double x, int y) {
    if (y) {
      double t = 0.5;
      for (int i = y; i--;) t *= 0.1;
      if (x >= 0)
        x += t;
      else
        x -= t, P('-');
      *this, (long long)(abs(x));
      P('.');
      if (x < 0) x = -x;
      while (y--) {
        x *= 10;
        x -= floor(x * 0.1) * 10;
        P(((int)x) % 10 + '0');
      }
    } else if (x >= 0)
      *this, (long long)(x + 0.5);
    else
      *this, (long long)(x - 0.5);
    ;
    return *this;
  }
  inline Fw &operator()(long double x, int y) {
    if (y) {
      double t = 0.5;
      for (int i = y; i--;) t *= 0.1;
      if (x >= 0)
        x += t;
      else
        x -= t, P('-');
      *this, (long long)(abs(x));
      P('.');
      if (x < 0) x = -x;
      while (y--) {
        x *= 10;
        x -= floor(x * 0.1) * 10;
        P(((int)x) % 10 + '0');
      }
    } else if (x >= 0)
      *this, (long long)(x + 0.5);
    else
      *this, (long long)(x - 0.5);
    ;
    return *this;
  }
};
Fw<Cp> out;
namespace flow {
const int N = 440, M = 2300;
struct edge {
  int to, ne, w;
} e[M];
int p[N], em, q[N], f[N], dep[N], w, vis[N], t;
inline void _add(int a, int b, int c) {
  e[em] = (edge){b, p[a], c};
  p[a] = em++;
}
inline void add(int a, int b, int c) { _add(a, b, c), _add(b, a, 0); }
inline void init() {
  em = 2;
  memset(p, 0, sizeof(p));
}
inline bool dfs(int S, int T, int fl) {
  if (S == T) {
    w = fl;
    return 1;
  }
  for (int &i = f[S]; i; i = e[i].ne)
    if (dep[e[i].to] == dep[S] + 1 && e[i].w) {
      if (dfs(e[i].to, T, min(fl, e[i].w))) {
        e[i].w -= w;
        e[i ^ 1].w += w;
        return 1;
      }
    }
  dep[S] = -1;
  return 0;
}
inline int dinic(int S, int T) {
  int res = 0;
  while (1) {
    int qe = 1;
    q[0] = S;
    ++t;
    vis[S] = t;
    for (int i = 0; i < qe; i++) {
      for (int j = p[q[i]]; j; j = e[j].ne)
        if (e[j].w && vis[e[j].to] != t)
          vis[e[j].to] = t, q[qe++] = e[j].to, dep[e[j].to] = dep[q[i]] + 1;
    }
    if (vis[T] != t) break;
    memcpy(f, p, sizeof(f));
    while (1) {
      if (!dfs(S, T, 19260817)) break;
      res += w;
    }
  }
  return res;
}
};  // namespace flow
const int N = 200007;
struct edge {
  int x, y;
} e[N], g[7], as[7];
char tmp[10];
int n, f[7][7], fa[7], po[7], ma, u[7][7];
std::vector<edge> h[7][7];
std::vector<int> d[7];
bool hans;
inline int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
bool debug;
int CNT;
inline void solve(int x, int y, int tot) {
  if (hans) return;
  if (y > ma) ++x, y = x + 1;
  if (x > ma) {
    if (tot + 1 < ma) return;
    flow::init();
    int S = 0, T = 1;
    tot = 0;
    for (int i = 1, iend = ma; i <= iend; i++) flow::add(S, i + 1, d[i].size());
    for (int i = 1, iend = ma; i <= iend; i++)
      for (int j = 1, jend = ma; j <= jend; j++)
        if (f[i][j]) {
          tot += f[i][j];
          flow::add(i * ma + j + 1, T, f[i][j]);
          flow::add(i + 1, i * ma + j + 1, 19260817);
          flow::add(j + 1, i * ma + j + 1, 19260817);
        }
    int fl = flow::dinic(S, T);
    if (hans |= fl == tot) memcpy(as, g, sizeof(as)), memcpy(u, f, sizeof(u));
    return;
  }
  if (!f[x][y] || find(x) == find(y)) {
    solve(x, y + 1, tot);
    return;
  }
  int ft[7];
  memcpy(ft, fa, sizeof(ft));
  f[x][y]--;
  fa[fa[x]] = fa[y];
  g[tot] = (edge){x, y};
  solve(x, y + 1, tot + 1);
  memcpy(fa, ft, sizeof(fa));
  f[x][y]++;
  solve(x, y + 1, tot);
}
int main() {
  in, n;
  for (int i = 0, iend = n - 1; i < iend; i++) {
    in, tmp;
    e[i].x = strlen(tmp);
    in, tmp;
    e[i].y = strlen(tmp);
    if (n == 150123 && i == 0 && e[i].x != 6) debug = 1;
    int x = e[i].x, y = e[i].y;
    if (x > y) std::swap(x, y);
    f[x][y]++;
  }
  for (int i = 1, iend = n; i <= iend; i++) {
    int c = 0;
    for (int x = i; x; x /= 10) c++;
    d[c].push_back(i);
    repr(ma, c);
  }
  for (int i = 1, iend = ma; i <= iend; i++) {
    if (f[i][i] >= d[i].size()) {
      out, "-1";
      return 0;
    }
    for (; f[i][i]; f[i][i]--) {
      h[i][i].push_back((edge){d[i].back(), d[i][0]});
      d[i].pop_back();
    }
  }
  for (int i = 1, iend = ma; i <= iend; i++) fa[i] = i;
  for (int i = 1, iend = ma; i <= iend; i++)
    po[i] = d[i].back(), d[i].pop_back();
  solve(1, 2, 0);
  if (!hans) {
    out, "-1";
    return 0;
  }
  for (int i = 1, iend = ma; i <= iend; i++)
    for (int j = 1, jend = ma; j <= jend; j++)
      if (u[i][j]) {
        for (int k = flow::p[i * ma + j + 1]; k; k = flow::e[k].ne)
          if (flow::e[k].w) {
            int x = flow::e[k].to - 1, y, z = flow::e[k].w;
            if (x == i)
              y = j;
            else
              y = i;
            if (x < y) {
              while (z--)
                h[x][y].push_back((edge){d[x].back(), po[y]}), d[x].pop_back();
            } else {
              while (z--)
                h[y][x].push_back((edge){po[y], d[x].back()}), d[x].pop_back();
            }
          }
      }
  for (int i = 0, iend = ma - 1; i < iend; i++) {
    int x = as[i].x, y = as[i].y;
    if (x > y) std::swap(x, y);
    h[x][y].push_back((edge){po[x], po[y]});
  }
  for (int i = 0, iend = n - 1; i < iend; i++) {
    int x = e[i].x, y = e[i].y;
    if (x < y) {
      out, h[x][y].back().x, ' ', h[x][y].back().y, '\n';
      h[x][y].pop_back();
    } else {
      out, h[y][x].back().y, ' ', h[y][x].back().x, '\n';
      h[y][x].pop_back();
    }
  }
}
