/*~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=
*$* WRITER:kakitamasziru/OxOmisosiru *$*
~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=*/
#ifdef LOCAL_JUDGE
#define _GLIBCXX_DEBUG
#endif
#include <iostream> // cout, endl, cin
#include <string> // string, to_string, stoi
#include <vector> // vector
#include <algorithm> // min, max, swap, sort, reverse, lower_bound, upper_bound
#include <utility> // pair, make_pair
#include <tuple> // tuple, make_tuple
#include <cstdint> // int64_t, int*_t
#include <limits>//setprecision
#include <map> // map
#include <queue> // queue, priority_queue
#include <set> // set,multiset
#include <stack> // stack
#include <deque> // deque
#include <math.h>//pow,,,
#include <cmath>//abs,,,
#include <bitset> // bitset
#include <numeric> //accumulate,,,
#define endl "\n";
using namespace std;

const long long INF = 4000000000000000001;
const int inf = 1001001001;
long long MOD = 1000000007;
typedef pair<long long,long long> P;

void chmax(long long &a,long long b){if(a < b) a = b;}
void chmin(long long &a,long long b){if(a > b) a = b;}

//Solve N^M. This, mod_pow use Iterative Square Method.
long long mod_pow(long long N, long long M) {
    if (M == 0) return 1;
    long long res = mod_pow((N * N) % MOD, M / 2);
    //When end-of-a bit is 1, times simple N.
    if (M & 1) res = (res * N) % MOD;
    return res %= MOD;
}
long long gcd(long long a, long long b) {
    if (b == 0) return a; else return gcd(b, a % b);
}
long long lcm(long long a, long long b) {
    return a / gcd(a, b) * b ;
}

int indegree[1000005];
vector<vector<int>> Edge(1000005);
vector<bool> seen(1000005,true);

int main() {
    ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;cin >> N;
    for(int i = 0;i<1000005;i++) indegree[i] = 0;
    for(int i = 0;i<N;i++){
        int prv = -1;
        for(int j = 0;j<N-1;j++){
            int from = i,to;cin >> to;to--;
            if(from > to) swap(from,to);
            //試合を頂点として見る from VS toをpairで保存するのだるいので、
            //試合番号をfrom*N+toとする
            int id = from*N+to;
            if(j > 0){
                Edge.at(prv).push_back(id);
            }
            if(j != 0 && indegree[id] != 0) indegree[id]++;
            else if(j != 0 && indegree[id] == 0) indegree[id] = 1;
            prv = id;
        }
    }
    queue<pair<int,int>> non_indegree;
    for(int i = 0;i<N;i++){
        for(int j = i+1;j<N;j++){
            int id = i*N+j;
            if(indegree[id] == 0 && i < j){
                //入次数0ならqueueに突っ込む
                non_indegree.push(make_pair(id,1));
                seen.at(id) = true;
            }
            else{
                seen.at(id) = false;
            }
        }
    }
    if(non_indegree.empty()){
        //入次数0の頂点がない=閉路があるので、順序が決まっているはずの試合進行に矛盾が生じる
        cout << -1 << endl;
        return 0;
    }
    int ans = 1;
    //トポロジカルソートをする
    while(!non_indegree.empty()){
        int from = non_indegree.front().first;
        int cnt = non_indegree.front().second;
        ans = max(ans,cnt);
        non_indegree.pop();
        seen.at(from) = true;
        //cout << ans << endl;
        for(int to : Edge.at(from)){
            indegree[to]--;
            if(indegree[to] == 0){
                seen.at(to) = true;
                non_indegree.push(make_pair(to,cnt+1));
            }
        }
    }
    for(int i = 2;i<(N-2)*(N-2)+N-1;i++){
        if(!seen.at(i)){
            cout << -1 << endl;
            return 0;
        }
    }
    cout << ans << endl;
}


Measured memory_bytes: 46216