/**    * Author: Daniel    * Created Time: 2021-03-13 13:41:37   **/      // time-limit: 2000   #include <bits/stdc++.h>      using namespace std;      #define F first    #define S second   #define ER erase   #define IS insert   #define PI acos(-1)   #define PB pop_back   #define EB emplace_back   #define lowbit(x) (x & -x)   #define SZ(x) ((int)x.size())   #define MP(x, y) make_pair(x, y)   #define ALL(x) x.begin(), x.end()   #define RALL(x) x.rbegin(), x.rend()   #define SOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cout<<fixed<<setprecision(10)      typedef long long LL;   typedef vector<LL> VL;   typedef vector<int> VI;   typedef pair<LL, LL> PLL;   typedef pair<int, int> PII;   typedef unsigned long long ULL;   typedef pair<double, double> PDD;   typedef vector<pair<int, int> > VPII;      template <typename A> using VE = vector<A>;   template <typename A> using USET = unordered_set<A>;   template <typename A> using HEAP = priority_queue<A>;   template <typename A, typename B> using PA = pair<A, B>;   template <typename A, typename B> using UMAP = unordered_map<A, B>;   template <typename A> using RHEAP = priority_queue<A, vector<A>, greater<A> >;      template <typename A, typename B>   string to_string(pair<A, B> p);      template <typename A, typename B, typename C>   string to_string(tuple<A, B, C> p);      template <typename A, typename B, typename C, typename D>   string to_string(tuple<A, B, C, D> p);      string to_string(const string& s) { return     + s +    ; }      string to_string(const char* s) { return to_string((string)s); }       string to_string(const char c) { return to_string((string)   + c); }       string to_string(bool b) { return (b ?  true  :  false ); }      string to_string(vector<bool> v)    {       bool first = true;       string res =  { ;       for (int i = 0; i < static_cast<int>(v.size()); i++)        {           if (!first) res +=  ,  ;           first = false;           res += to_string(v[i]);       }       res +=  } ;       return res;   }      template <size_t N>   string to_string(bitset<N> v)   {       string res =   ;       for (size_t i = 0; i < N; i++) res += static_cast<char>( 0  + v[i]);       return res;   }      template <typename A>   string to_string(A v)   {       bool first = true;       string res =  { ;       for (const auto &x : v)       {           if (!first) res +=  ,  ;           first = false;           res += to_string(x);       }       res +=  } ;       return res;   }      template <typename A, typename B>   string to_string(pair<A, B> p) { return  (  + to_string(p.first) +  ,   + to_string(p.second) +  ) ; }      template <typename A, typename B, typename C>   string to_string(tuple<A, B, C> p) { return  (  + to_string(get<0>(p)) +  ,   + to_string(get<1>(p)) +  ,   + to_string(get<2>(p)) +  ) ; }      template <typename A, typename B, typename C, typename D>   string to_string(tuple<A, B, C, D> p) { return  (  + to_string(get<0>(p)) +  ,   + to_string(get<1>(p)) +  ,   + to_string(get<2>(p)) +  ,   + to_string(get<3>(p)) +  ) ; }      void debug_out() { cout <<   n ; }      template <typename Head, typename... Tail>   void debug_out(Head H, Tail... T) { cout <<     << to_string(H); debug_out(T...); }      #ifdef LOCAL   #define debug(...) cout <<  [  << #__VA_ARGS__ <<  ]: , debug_out(__VA_ARGS__)   #else   #define debug(...) 42   #endif      ///////////////////////////////////////////////////////////////////////////   //////////////////// DO NOT TOUCH BEFORE THIS LINE ////////////////////////   ///////////////////////////////////////////////////////////////////////////      // check the limitation!!!   const int N = 5010, M = 1010;      int n;   int a[N][N];   int res[N];   int p[N];   struct Node   {       int u, v, val;       bool operator<(const Node &t) const       {           if (val != t.val) return val < t.val;           else return u < t.u;       }   };      int find(int x)   {       if (x != p[x]) p[x] = find(p[x]);       return p[x];   }      // read the question carefully!!!   int main()   {       SOS;          cin >> n;       for (int i = 1; i <= n; i ++ )           for (int j = 1; j <= n; j ++ )               cin >> a[i][j];       VE<Node> b;       for (int i = 1; i <= n; i ++ )           for (int j = i; j <= n; j ++ )               b.EB((Node){i, j, a[i][j]});       sort(ALL(b));       VPII edge;       int m = n;       for (int i = 1; i <= n; i ++ )        {           p[i] = i;           res[i] = a[i][i];       }       for (auto [u, v, val] : b)       {           int pa = find(u), pb = find(v);           if (pa == pb) continue;           else if (val == res[pb])           {               p[pa] = pb;               edge.EB(pa, pb);           }           else if (val == res[pa])           {               p[pb] = pa;               edge.EB(pb, pa);           }           else           {               p[pa] = p[pb] = ++ m;               p[m] = m;               res[m] = val;               edge.EB(pa, m);               edge.EB(pb, m);           }       }       cout << m <<   n ;       for (int i = 1; i <= m; i ++ )       {           cout << res[i];           cout <<    n [i == m];       }       cout << find(1) <<   n ;       for (auto [x, y] : edge) cout << x <<     << y <<   n ;       return 0;   }      // GOOD LUCK!!!