#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;   }