// Original C++ solution (slower):
// https://atcoder.jp/contests/abc139/submissions/7298310



#include <iostream>

#include <vector>



using namespace std;

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



int main(void){

    ios::sync_with_stdio(false);

    cin.tie(nullptr);

    int n;

    cin >> n;

    int a[1010][1010] = {};

    int head[1010] = {};

    rep(i,n){

        rep(j,n-1){

            int x;

            cin >> x;

            x--;

            a[i][j] = x;

        }

    }

    int turn = 0;

    int used[1010] = {};

    for (int i = 0; i < 1010; i++) used[i] = -1;

    while(true){

        bool ng = true;

        int empty_cnt = 0;

        rep(i,n){

            if (head[i] == n-1) {

                empty_cnt++;

                continue;

            }

            int j = a[i][head[i]];

            if (used[i] == turn || used[j] == turn) continue;

            if (a[j][head[j]] == i) {

                head[i]++;

                head[j]++;

                used[i] = used[j] = turn;

                ng = false;

            }

        }

        if (empty_cnt == n) break;

        if (ng) {

            cout << -1 << endl;

            return 0;

        }

        turn++;

    }

    cout << turn << endl;



    return 0;

}


// Optimized solution to the same problem (faster):
//https://atcoder.jp/contests/abc139/submissions/7282608



#include <bits/stdc++.h>

#pragma GCC optimize("O3")

#define REP(i,n) for(int i=0;i<n;i++)

#define REPP(i,n) for(int i=1;i<=n;i++)

const double PI = acos(-1);

const double EPS = 1e-15;

long long INF=(long long)1E17;

#define i_7 (long long)(1E9+7)

long mod(long a){

    long long c=a%i_7;

    if(c>=0)return c;

    return c+i_7;

}

using namespace std;

bool prime_(int n){

    if(n==1){

        return false;

    }else if(n==2){

        return true;

    }else{

        for(int i=2;i<=sqrt(n);i++){

            if(n%i==0){

                return false;

            }

        }

        return true;

    }

}



long long gcd_(long long a, long long b){

    if(a<b){

        swap(a,b);

    }

    if(a%b==0){

        return b;

    }else{

        return gcd_(b,a%b);

    }

}



long long lcm_(long long x, long long y){

    return (x/gcd_(x,y))*y;

}



class UnionFind {

public:

    //各頂点の親の番号を格納する。その頂点自身が親だった場合は-(その集合のサイズ)を入れる。

    vector<int> Parent;



    //クラスを作るときは、Parentの値を全て-1にする。

    //以下のようにすると全てバラバラの頂点として解釈できる。

    UnionFind(int N) {

        Parent = vector<int>(N, -1);

    }



    //Aがどのグループに属しているか調べる

    int root(int A) {

        if (Parent[A] < 0) return A;

        return Parent[A] = root(Parent[A]);

    }



    //自分のいるグループの頂点数を調べる

    int size(int A) {

        return -Parent[root(A)];//先祖をrootで取っておきたい。

    }



    //AとBをくっ付ける

    bool connect(int A, int B) {

        //AとBを直接つなぐのではなく、root(A)にroot(B)をくっつける

        A = root(A);

        B = root(B);

        if (A == B) {

            //すでにくっついてるからくっ付けない

            return false;

        }



        //大きい方(A)に小さいほう(B)をくっ付けたい

        //大小が逆だったらAとBをひっくり返す。

        if (size(A) < size(B)) swap(A, B);



        //Aのサイズを更新する

        Parent[A] += Parent[B];

        //Bの親をAに変更する

        Parent[B] = A;



        return true;

    }

};





int main(){

    ios::sync_with_stdio(false);

    cin.tie(0);

    int n;

    cin>>n;

    int a[n][n-1];

    REP(i,n){

        REP(j,n-1){

            cin>>a[i][j];

            a[i][j]--;

        }

    }

    int now[n]={};

    //bool used[n][n-1] = {};

    register int day = 0;

    register bool flag;

    register bool upgrade_;

    register int op;

    while(true){

        upgrade_ = false;

        flag = true;

        int visited[n] = {};

        REP(i,n){

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

            flag = false;

            if(visited[i])continue;

            op = a[i][now[i]];

            if(visited[op])continue;

            if(now[op]==n-1)continue;

            if(a[op][now[op]]==i){

                //used[i][now[i]] = true;

                now[i]++;

                visited[i] = true;

                //used[op][now[op]] = true;

                now[op]++;

                visited[op] = true;

                upgrade_ = true;

            }

        }

        if(flag)break;

        if(!upgrade_){

            day = -1;

            break;

        }else{

            day++;

        }

    }

    cout<<day<<endl;

    return 0;

}


// Fastest known solution for this problem: