#include <bits/stdc++.h>
using namespace std;
template <class T>
void splitstr(const string &s, vector<T> &out) {
  istringstream in(s);
  out.clear();
  copy(istream_iterator<T>(in), istream_iterator<T>(), back_inserter(out));
}
template <class T>
T gcd(T a, T b) {
  return b ? gcd(b, a % b) : a;
}
static void redirect(int argc, const char **argv) {
  ios::sync_with_stdio(false);
  cin.tie(NULL);
  if (argc > 1) {
    static filebuf f;
    f.open(argv[1], ios::in);
    cin.rdbuf(&f);
    if (!cin) {
      cerr << "Failed to open '" << argv[1] << "'" << endl;
      exit(1);
    }
  }
  if (argc > 2) {
    static filebuf f;
    f.open(argv[2], ios::out | ios::trunc);
    cout.rdbuf(&f);
    if (!cout) {
      cerr << "Failed to open '" << argv[2] << "'" << endl;
    }
  }
}
static void no() {
  cout << "-1\n";
  exit(0);
}
static void check_dist(const vector<int> &dist,
                       const vector<vector<int>> &edges, int cur, int parent,
                       int depth) {
  if (dist[cur] != depth) no();
  for (int v : edges[cur])
    if (v != parent) check_dist(dist, edges, v, cur, depth + 1);
}
int main(int argc, const char **argv) {
  redirect(argc, argv);
  int N, K;
  cin >> N >> K;
  vector<vector<int>> dist(K, vector<int>(N));
  vector<int> opos(K, -1);
  for (int i = 0; i < K; i++)
    for (int j = 0; j < N; j++) {
      cin >> dist[i][j];
      if (dist[i][j] == 0) opos[i] = j;
    }
  if (count(begin(opos), end(opos), -1)) no();
  int root = opos[0];
  vector<int> parent(N, -1);
  parent[root] = -2;
  vector<vector<int>> order(K);
  for (int i = 1; i < K; i++) {
    if (dist[i][root] == 0) no();
    order[i].resize(dist[i][root] + 1, -1);
    for (int j = 0; j < N; j++)
      if (dist[i][j] + dist[0][j] == dist[i][root]) order[i][dist[0][j]] = j;
    if (order[i][0] != root) no();
    for (int j = 1; j < ((long long)(order[i]).size()); j++) {
      int v = order[i][j];
      if (v == -1) no();
      if (parent[v] != -1 && parent[v] != order[i][j - 1]) no();
      parent[v] = order[i][j - 1];
    }
  }
  vector<vector<pair<int, int>>> down(N);
  for (int i = 0; i < N; i++)
    if (parent[i] == -1) {
      int hi = -1;
      int v = root;
      int d = dist[0][i];
      pair<int, int> best(0, 0);
      for (int j = 1; j < K; j++) {
        int a = dist[0][i] + dist[j][root] - dist[j][i];
        if (a < 0 || a > 2 * dist[j][root] || (a & 1)) no();
        a /= 2;
        if (a > hi) {
          hi = a;
          v = order[j][a];
          d = dist[0][i] - a;
        }
      }
      down[v].emplace_back(d, i);
    }
  vector<int> lvl;
  for (int i = 0; i < N; i++) {
    if (down[i].empty()) continue;
    sort(begin(down[i]), end(down[i]));
    lvl.clear();
    lvl.push_back(i);
    for (const auto &entry : down[i]) {
      int d = entry.first;
      int v = entry.second;
      if (d > ((long long)(lvl).size()))
        no();
      else {
        parent[v] = lvl[d - 1];
        if (d == ((long long)(lvl).size())) lvl.push_back(v);
      }
    }
  }
  vector<vector<int>> edges(N);
  for (int i = 0; i < N; i++) {
    if (parent[i] == -1)
      no();
    else if (parent[i] >= 0) {
      edges[parent[i]].push_back(i);
      edges[i].push_back(parent[i]);
    }
  }
  for (int i = 0; i < K; i++) check_dist(dist[i], edges, opos[i], -1, 0);
  for (int i = 0; i < N; i++)
    if (parent[i] >= 0) cout << i + 1 << ' ' << parent[i] + 1 << '\n';
  return 0;
}
