#include <bits/stdc++.h>

#define debug(x) cout <<"DEBUG"<<" "<< #x << ":" << x << '\n'
#define rep(i,n) for(int_fast32_t i = 0; i < ((int_fast32_t)(n)); i++)   // 0-indexed昇順
#define rep1(i,n) for(int_fast32_t i = 1; i <= ((int_fast32_t)(n)); i++) // 1-indexed昇順
#define rrep(i,n) for(int_fast32_t i = ((int_fast32_t)(n)-1); i >= 0; i--)  // 0-indexed降順
#define rrep1(i,n) for(int_fast32_t i = ((int_fast32_t)(n)); i >= 1; i--)   // 1-indexed降順
#define all(x) (x).begin(),(x).end()

using namespace std;

template<typename T>
using vec = vector<T>;
using i32 = int_fast32_t;
using i64 = int_fast64_t;
using u32 = uint_fast32_t;
using u64 = uint_fast64_t;
using ll = long long;
using ld = long double;
using vi = vec<int_fast32_t>;
using vl = vec<int_fast64_t>;
using vld = vec<ld>;
using vii = vec<vi>;  // 2次元配列
using PII = pair<int_fast32_t, int_fast32_t>;

template<class T>
using maxheap = std::priority_queue<T>;
template<class T>
using minheap = std::priority_queue<T, std::vector<T>, std::greater<T>>;

template<class T,class U> inline bool chmax(T &a, const U &b){if(a<b){a=b;return 1;}return 0;}
template<class T,class U> inline bool chmin(T &a, const U &b){if(a>b){a=b;return 1;}return 0;}

const ld Pi = std::acos(-1.0L);
constexpr ll infll = (1LL<<62)-1;
constexpr int inf = (1<<30)-1;
const int mod = 1000000007;
// const int mod = 998244353;

int n, a1, a2, gameID1, gameID2;
vec<vec<i32>> game_graph;
/*FUNCs=================================================*/
i32 calc_gameID(i32 a, i32 b) {
    return min(a,b) * n + max(a,b);
}

bool haveLoop, seen[1000005], finish[1000005];
void dfs(const vii &graph, i32 v, i32 pv) {
    seen[v] = true;
//    debug(v);  // debug
    for(auto nv : graph[v]) {
//        debug(nv);  // Debug
        if(nv == pv) continue;
        if(finish[nv]) continue;
        if(seen[nv] && !finish[nv]) {
            haveLoop = true;
            return;
        }
        dfs(graph, nv, v);

        if(haveLoop) return;
    }
    finish[v] = true;
}

i32 dist[1000005];
i32 dfs2(const vii &graph, i32 v, i32 pv) {
    if(dist[v] != -1) return dist[v];
    i32 ret = -1;
    for(auto nv : graph[v]) chmax(ret, dfs2(graph, nv, v)+1);
    return dist[v] = ret;
}
/*MAIN==================================================*/
signed main(){
    int START_TIME = clock();
    cin.tie(nullptr);
    ios::sync_with_stdio(false);   //cin cout 高速化
//    cout << fixed << setprecision(15);

    // input and construct
    cin >> n;
    game_graph.resize(n*n+1);
    vec<bool> isroot(n*n+1, true);
    for(i32 i = 0; i < n; ++i) {
        cin >> a1;
        --a1;
        for(i32 j = 0; j < n-1 -1; ++j) {
            cin >> a2;
            --a2;
            gameID1 = calc_gameID(i, a1);
            gameID2 = calc_gameID(i, a2);
            game_graph[gameID1].push_back(gameID2);
            isroot[gameID2] = false;
            a1 = a2;
        }
    }
    for(i32 i = 0; i < isroot.size(); ++i) {
        if(i == (n-1)*(n+1)) continue;
        if(isroot[i] && !game_graph[i].empty()) game_graph[(n-1)*(n+1)].push_back(i);
    }
//    // Debug
//    for(auto v : game_graph) {
//        if(!v.size()) continue;
//        for(auto u : v) cout << u << ' ';
//        cout << '\n';
//    }

    // loop check
    haveLoop = false;
    memset(seen, 0, sizeof(seen));
    memset(finish, 0, sizeof(finish));
    dfs(game_graph, (n-1)*(n+1), -1);
    if(haveLoop) {
        cout << -1 << '\n';
        return 0;
    }
    haveLoop = true;
    for(i32 i = 0; i < isroot.size(); ++i) {
        if(i == (n-1)*(n+1)) continue;
        if(isroot[i] && !game_graph[i].empty()) haveLoop = false;
    }
    if(haveLoop) {
        cout << -1 << '\n';
        return 0;
    }

    // calc longest path's length
    memset(dist, -1, sizeof(dist));
    i32 answer = dfs2(game_graph, (n-1)*(n+1), -1);
    cout << answer+1 << '\n';

    // printf("ExecutionTime: %d /ms\n",1000*(int)((clock()-START_TIME)/CLOCKS_PER_SEC));
}


Measured memory_bytes: 49280