#include <vector>
#include <iostream>
#include <cmath>
#include <iomanip>
#include <string>
#include <utility>
#include <stack>
#include <numeric>
#include <random>
#include <algorithm>
#include <queue>
#include <functional>
#include <iterator>
#include <list>
#include <unordered_map>
#include <deque>
#include <math.h>
#include <tgmath.h>
#include <cstdlib>
using namespace std;

#define all(x) (x).begin(), (x).end()
#define rep(i, b, e) for(i = b; i < e; ++i)
#define repr(i, b, e) for (i = b; i >= e; --i)
#define ull unsigned long long int
#define ll long long int
#define pint pair<int, int>

#define M_DEBUG 1
#define PI 3.141592653589793

#define E '\n'

#define printt(x) cout << (x) << endl;
#define printa(x,n) for(int i = 0; i < n; i++){ cout << (x[i]) << "\n";}
#define INF (1e18)

const ll MAX = 1000000000;
const ll MOD = 1e9 + 7;

ll a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z;

template<class T> inline bool chmin(T& a, T b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template<class T> inline bool chmax(T& a, T b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}

ll aabs(ll a) {
    if (a < 0) return -a;
    return a;
}

//fast power
ll calc(ll a, ll b) {
    if (b == 0) return 1;
    else if (b % 2 == 0) {
        ll d = calc(a, b / 2);
        return (d * d) % MOD;
    }
    else return (a * calc(a, b - 1)) % MOD;
}

//fast combination
ll comb(ll n, ll a) {
    ll b = 1, c = 1;
    for (ll i = 1; i <= a; ++i) {
        b = b * i % MOD;
        c = c * (n - i + 1) % MOD;
    }

    return c * calc(b, MOD - 2) % MOD;
}

ll comb2(ll a) {
    ll b = a / 2;
    if (a % 2) {
        b = (a - 1) / 2;
        return (b * a);
    }
    return (b * (a - 1));
}

int dfs(int x, int y, int z) {
    if (x == a && y == b && z == c) return 1;
    
    int ans = 0;
    if (x != a) ans += dfs(x + 1, y, z);
    if (x >= y + 1/* && y != b*/) ans += dfs(x, y + 1, z);
    if (y >= z + 1/* && z != c*/) ans += dfs(x, y, z + 1); 

    return ans;
}

uint64_t gcd_impl( uint64_t n, uint64_t m ) {
        for( int i = 0; i < 10; ++i ) {
                uint64_t t = n - m;
                bool q = m > t;
                n = q ? m : t;
                m = q ? t : m;
                if( m == 0 ) { return n; }
        }
        return gcd_impl( m, n % m );
}

uint64_t gcd( uint64_t n, uint64_t m ) {
        return n > m ? gcd_impl( n, m ) : gcd_impl( m, n );
}

const int INF_ = 1e+7;

//0-indexed

struct Node {
    std::vector<int> nodes;
    std::vector<int> edge_costs;

    int num = 0;
    int cost = INF_;
    int link_out = 0;
    int link_in = 0;
    int pcost = 0;
};

class Graph {
public:
    Graph(int n, bool directed);
    ~Graph();

    void setGraph(int n, int node, int edge_cost);
    void Dijkstra(int start);
    void print();
    std::vector<int> topologicalSort();

    int longestPath();

    int ans = 0;

private:
    std::vector<Node> m_graph;
    int m_size;
    bool m_directed = false;
};


Graph::Graph(int n, bool directed) : m_size(n), m_directed(directed) {
    m_graph = std::vector<Node>(m_size);
}

Graph::~Graph(){}

void Graph::setGraph(int n, int node, int edge_cost) {
    --n;
    --node;
    ++m_graph[node].link_in;
    m_graph[n].nodes.emplace_back(node);
    m_graph[n].edge_costs.emplace_back(edge_cost);
    ++m_graph[n].link_out;
}

void Graph::Dijkstra(int start) {
    m_graph[start].cost = 0;
    std::queue<int> q;
    q.push(start);
    while (!q.empty()) {
        int qi = q.front();q.pop();

        for (int i = 0; i < m_graph[qi].nodes.size(); ++i) {
            int qqi = m_graph[qi].nodes[i], new_cost = m_graph[qi].edge_costs[i] + m_graph[qi].cost;
            if (m_graph[qqi].cost > new_cost) {
                m_graph[qqi].cost = new_cost;
                q.push(qqi);
            }
        }
    }
}

int Graph::longestPath() {
    int mx = 0;
    for (auto&& g : m_graph) {
        if (g.pcost > mx) mx = g.pcost;
    }
    return mx;
}

void Graph::print() {
    for (int i = 0; i < m_size; ++i) {  
        std::cout << i + 1 << " : ";
        for (int j = 0; j < m_graph[i].nodes.size(); ++j) 
            std::cout << m_graph[i].nodes[j] + 1 << ", ";
        std::cout << std::endl;
    }

    for (int i = 0; i < m_size; ++i) 
        std::cout << i + 1 << " : " << m_graph[i].link_in << ", " << m_graph[i].link_out << std::endl;
}

std::vector<int> Graph::topologicalSort() {
    std::queue<int> q;        
    for (int i = 0; i < m_size; ++i)
        if (m_graph[i].link_in == 0) {
            q.push(i);
            m_graph[i].pcost = 1;
        }

    std::vector<int> topo;
    std::vector<int> tmp(m_size);
    for (int i = 0; i < m_size; ++i) tmp[i] = m_graph[i].link_in;

    while (!q.empty()) {
        
        int i = q.front();q.pop();
        topo.emplace_back(i);

        for (auto&& j : m_graph[i].nodes) {
            m_graph[j].link_in--;
            if (m_graph[j].link_in == 0) {
                q.push(j);
                m_graph[j].pcost = m_graph[i].pcost + 1;
            }
        }
    }

    for (int i = 0; i < m_size; ++i) m_graph[i].link_in = tmp[i];

    return topo;
}

struct HashPair {

    //注意 constがいる
    template<class T1, class T2>
    size_t operator()(const pair<T1, T2> &p) const {

        //first分をハッシュ化する
        auto hash1 = hash<T1>{}(p.first);

        //second分をハッシュ化する
        auto hash2 = hash<T2>{}(p.second);

        //重複しないようにハッシュ処理
        size_t seed = 0;
        seed ^= hash1 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
        seed ^= hash2 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
        return seed;
    }
};

int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    cin >> n;
    Graph g(n * (n - 1) / 2, true);
    k = 1;
    unordered_map<pair<int, int>, int, HashPair> um;
    rep (i, 1, n + 1) {
        rep (j, 1, n + 1) {
            if (i == j) continue;
            if (i > j) {
                a = j;
                b = i;
            } else {
                a = i;
                b = j;
            }
            if (um[make_pair(a, b)] == 0) {
                um[make_pair(a, b)] = k;
                ++k;
            }
        }
    }


    rep (i, 1, n + 1) {
        int aa;
        std::vector<pair<int, int> > vp;
        rep (j, 0, n - 1) {
            cin >> a;
            if (i > a) {
                aa = a;
                b = i;
            } else {
                aa = i;
                b = a;
            }
            vp.emplace_back(make_pair(aa, b));
        }
        for (int j = 1; j < vp.size(); ++j) {
            //cout << um[vp[j - 1]] << "->" << um[vp[j]] << endl;
            g.setGraph(um[vp[j - 1]], um[vp[j]], 0); 
        }
    }
    vector<int> topo = g.topologicalSort();

    if (topo.size() !=  n * (n - 1) / 2) {
        cout << -1 << endl;
        return 0;
    }

    cout << g.longestPath() << endl;

    return 0;
}



Measured memory_bytes: 100084