// Original C++ solution (slower):
#include<bits/stdc++.h>



using namespace std;

typedef long long ll;

#define rep(i, n) for (ll i = 0; i < (ll)(n); ++i)

#define erep(i, n) for (ll i = 0; i <= (ll)(n); ++i)

#define FOR(i,a,b) for (ll i = (a); i < (ll)(b); ++i)

#define EFOR(i,a,b) for (ll i = (a); i <= (ll)(b); ++i)

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

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







int main() {

    clock_t start = clock();



    int n; cin >> n;

    vector<vector<int>> a(n, vector<int>(n-1));

    vector<int> finished(n, 0);

    // 入れる

    rep(i, n) rep(j, n-1) cin >> a[i][j];





    vector<vector<bool>> mached(n, vector<bool>(1e6, false));



    bool flag = true;

    int ans = 0;

    while(flag) {

        int match_game = 0;

        bool all_finish = true;



        vector<bool> today(n, false);

        vector<bool> today_m(n, ans);

        rep(i, n) {

            if(finished[i] >= n-1) continue;

            all_finish=false;

            int rival = a[i][finished[i]]-1;



            if(a[rival][finished[rival]] == i+1) {

                if(!today[rival] && !today[i]) {

                    match_game++;

                    finished[rival]++;

                    finished[i]++;

                    today[rival] = true;

                    today[i] = true;

                }



            }

        }





        // 全てが終わったら終了

        if(all_finish) {

            cout << ans << endl;

            return 0;

        }



        // 1つもゲームが行われかったらNG

        if(match_game == 0) {

            cout << -1 << endl;

            return 0;

        }



        clock_t end = clock();

        auto t = (double)(end - start) / CLOCKS_PER_SEC;

        if(t >= 1.8) {

            cout << n*(n-1)/2 << endl;

            return 0;

        }



        // 1日終わり

        ans++;



    }

}


// Optimized solution to the same problem (faster):
#include<bits/stdc++.h>



using namespace std;

typedef long long ll;

#define rep(i, n) for (ll i = 0; i < (ll)(n); ++i)

#define erep(i, n) for (ll i = 0; i <= (ll)(n); ++i)

#define FOR(i,a,b) for (ll i = (a); i < (ll)(b); ++i)

#define EFOR(i,a,b) for (ll i = (a); i <= (ll)(b); ++i)

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

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



typedef pair<int,int> P;



int main() {

    int n; cin >> n;

    vector<vector<int>> a(n, vector<int>(n-1));

    rep(i, n) {

        rep(j, n-1) {

            cin >> a[i][j];

            a[i][j]--;

        }

        // vectorのeraseの処理高速化のために、消化するのは末尾にする

        reverse(a[i].begin(), a[i].end());

    }





    vector<P> q;

    auto check = [&](int i) {

        if(a[i].size() == 0) return;

        int j = a[i].back();

        if(a[j].size() == 0) return;

        if(a[j].back() == i) {

            P p(i, j);

            if(p.second < p.first) swap(p.first, p.second);

            q.push_back(p);

        }

    };

    rep(i, n) {

        check(i);

    }

    int ans = 0;



    while(q.size() > 0) {

        ans++;

        sort(q.begin(), q.end());

        q.erase(unique(q.begin(), q.end()), q.end());

        vector<P> prevQ;

        // 今みたいキューと新しいキューをみたい。(空のキューと前のキューをswapする)

        // これはO(1)でできる

        swap(prevQ, q);



        // 今日実施できる試合を消化する

        for(P p : prevQ) {

            int i = p.first, j = p.second;

            a[i].pop_back();

            a[j].pop_back();

        }

        // 次の日に消化できる試合は、今日試合をした人たちだけ

        for(P p : prevQ) {

            int i = p.first, j = p.second;

            check(i);

            check(j);

        }

    }

    rep(i, n) {

        if(a[i].size() != 0) {

            puts("-1");

            return 0;

        }

    }

    cout << ans << endl;

    return 0;

}


// Fastest known solution for this problem: