#include <iostream>
#include <iomanip>
#include <random>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <cmath>
#include <numeric>
#include <cstdlib>
#include <cstring>
#include <deque>
#include <sstream>
#include <bitset>
#include <cassert>
#include <fstream>
#include <queue>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <limits>

#define len(X) ((int)(X).size())

#ifdef __LOCAL
#define DBG(X) cout << #X << "=" << (X) << '\n';
#define SAY(X) cout << (X) << '\n';
#else
#define DBG(X)
#define SAY(X)
#endif

#define M_PI       3.14159265358979323846

using namespace std;

using ll = long long int;
using ull = unsigned long long int;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;

const int INT_INF = (int)(2e9);
const ll  LL_INF = (ll)(2e18);

const int NIL = -1;
static mt19937 _g(time(nullptr));

inline ll randint(ll a, ll b) { ll w = (_g() << 31LL) ^ _g(); return a + w % (b - a + 1); }
inline void fast_io() { ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); };
template<typename T> inline T sign(T x) { return T(x > 0) - T(x < 0); }
template<typename T, typename S> inline ostream& operator<<(ostream& os, const pair<T, S> p) { cout << "[" << p.first << ";" << p.second << "]"; return os; }
template<typename T> inline ostream& operator<<(ostream& os, const vector<T>& v) { for (auto el : v) cout << el << " "; return os; }
template<typename T> inline T fetch() { T ret; cin >> ret; return ret; }
template<typename T> inline vector<T> fetch_vec(int sz) { vector<T> ret(sz); for (auto& elem : ret) cin >> elem; return ret; }

bool ts(std::unordered_map<int, vector<int>>& graph,
    int start,
    std::unordered_set<int>& visited,
    std::unordered_set<int>& back,
    std::vector<int>& days)
{
    //std::cout << start << " ";

    visited.insert(start);
    back.insert(start);

    for (int adj : graph[start])
    {
        if (back.count(adj) != 0) return false;

        if (visited.count(adj) == 0)
        {
            if (!ts(graph, adj, visited, back, days))
                return false;
        }
        days[start] = std::max(days[start], days[adj] + 1);
    }

    back.erase(start);

    return true;
}


int getMatchId(int N, int team1, int team2)
{
    if (team1 > team2)
        std::swap(team1, team2);

    return team1 + team2 * N;
}

int solve()
{
    int N;

    std::cin >> N;

    const int maxComb = N * (N + 1);

    std::unordered_map<int, vector<int>> graph;

    for (int i = 1; i < N + 1; ++i)
    {
        int secondTeam;
        std::cin >> secondTeam;

        int prevMatch = getMatchId(N, i, secondTeam);

        for (int j = 2; j < N; ++j)
        {
            std::cin >> secondTeam;
            int currMatch = getMatchId(N, i, secondTeam);

            graph[prevMatch].push_back(currMatch);
            prevMatch = currMatch;
        }
    }

    std::vector<int> days(maxComb, 1);
    std::unordered_set<int> visited;
    std::unordered_set<int> back;
    int maxDays = 0;

    for (int i = 0; i < maxComb; ++i)
    {
        if (visited.count(i) == 0 && !graph[i].empty())
        {
            if (!ts(graph, i, visited, back, days))
                return -1;
            
            maxDays = std::max(maxDays, days[i]);

            //std::cout << std::endl;
        }
    }

    return maxDays;
}

int main()
{
    std::cout << solve() << std::endl;

    return 0;
}


Measured memory_bytes: 94736