#include <bits/stdc++.h>
using namespace std;
const int Maxn = 3e4 + 5;
const int Maxm = 2e2 + 5;
int n, k, rt = 0;
int vis[Maxn], dep[Maxn], fa[Maxn], node[Maxn], len[Maxm][Maxn],
    tree[Maxm][Maxn];
vector<int> vec[Maxn], Tree[Maxn];
struct point {
  int dep, id;
} a[Maxn];
bool cmp(point x, point y) { return x.dep < y.dep; }
inline void output() {
  cout << -1 << endl;
  exit(0);
}
inline void init() {
  memset(a, 0, sizeof a);
  memset(vis, 0, sizeof vis);
  memset(node, 0, sizeof node);
  memset(tree, 0, sizeof tree);
  memset(fa, 0, sizeof fa);
  cin >> n >> k;
  for (int i = 1; i <= n; i++) Tree[i].clear(), vec[i].clear();
  for (int i = 1; i <= n; i++) {
    a[i].id = i;
    scanf("%d", &a[i].dep);
    dep[i] = a[i].dep;
    if (a[i].dep == 0) {
      if (rt == 0)
        rt = i;
      else
        output();
    }
  }
  rt == 0 ? output() : Tree[rt].push_back(rt), fa[rt] = rt;
  for (int i = 1; i < k; i++) {
    for (int j = 1; j <= n; j++) {
      scanf("%d", &len[i][j]);
      if (len[i][j] == 0) {
        if (node[i] == 0)
          node[i] = j;
        else
          output();
      }
    }
    if (node[i] == 0) output();
  }
}
inline int lca(int x, int y) {
  int d1 = dep[node[x]], d2 = dep[y], l = len[x][y];
  if (d1 + d2 < l || d1 + l < d2 || d2 + l < d1 || ((d1 + d2 + l) & 1))
    output();
  return (d1 + d2 - l) / 2;
}
inline void mk_fa(int x, int y) {
  fa[x] = y;
  vec[x].push_back(y);
  vec[y].push_back(x);
}
inline void build() {
  for (int i = 1; i < k; i++) {
    for (int j = 1; j <= n; j++) {
      if (a[j].dep + len[i][j] == a[node[i]].dep) {
        if (tree[i][a[j].dep]) output();
        tree[i][a[j].dep] = j;
        if (Tree[j].empty()) Tree[j].push_back(j);
      }
    }
  }
  for (int i = 1; i < k; i++) {
    for (int d = 1; d <= a[node[i]].dep; d++) {
      if (tree[i][d] == 0 || fa[tree[i][d]] != tree[i][d - 1] && fa[tree[i][d]])
        output();
      else
        mk_fa(tree[i][d], tree[i][d - 1]);
    }
  }
  sort(a + 1, a + n + 1, cmp);
  for (int I = 1; I <= n; I++) {
    int i = a[I].id;
    if (fa[i]) continue;
    int ma = 0, Rt = rt, d = dep[i];
    for (int j = 1; j < k; j++) {
      if (lca(j, i) > ma) {
        ma = lca(j, i), Rt = tree[j][ma];
        d = dep[i] - ma;
      }
    }
    Tree[Rt].size() < d ? output() : mk_fa(i, Tree[Rt][d - 1]);
    if (Tree[Rt].size() == d) {
      Tree[Rt].push_back(i);
    }
  }
}
void dfs(int Rt, int x, int dep) {
  vis[x] = 1;
  if (dep != len[Rt][x]) output();
  for (int i = 0; i < vec[x].size(); i++) {
    if (!vis[vec[x][i]]) dfs(Rt, vec[x][i], dep + 1);
  }
}
inline void check() {
  for (int i = 1; i < k; i++) {
    memset(vis, 0, sizeof vis);
    dfs(i, node[i], 0);
  }
}
inline void print() {
  for (int i = 1; i <= n; i++) {
    if (fa[i] != i) printf("%d %d\n", i, fa[i]);
  }
}
int main() {
  init();
  build();
  check();
  print();
}
