#include "bits/stdc++.h"

#define REP(i,num) for(int i=0;i<(num);++i)
#define ALL(c) c.begin(),c.end()
#define PRINTALL(c) for(auto& x:c){cout<<x<<' ';}cout<<endl;
#define PAIRCOMP(c,comp) [](const pair<ll,ll>& lhs,const pair<ll,ll>& rhs){return lhs.c comp rhs.c;}

constexpr int atcoder_mod = 1e9+7;

using namespace std;
using ll = long long;

template<typename T=int>
T in(){T x; cin >> x; return (x);}
template<typename T=int,typename C=vector<T>>
C vecin(int N){C x(N);REP(i,N){x[i]=in<T>();}return move(x);}

void vout(){cout << endl;}
template<typename Head,typename... Tail>
void vout(Head&& h,Tail&&... t){cout << ' ' << h;vout(forward<Tail>(t)...);}
void out(){cout << endl;}
template<typename Head,typename... Tail>
void out(Head&& h,Tail&&... t){cout << h;vout(forward<Tail>(t)...);}

auto comp = [](const pair<int,int>& l,const pair<int,int>& r){return l.first==r.first ? l.second<r.second : l.first<r.first;};
map<pair<int,int>,int,decltype(comp)> mindex(comp);

class ConnectNodeInfo{
	vector<vector<pair<ll,ll>>> graph;
public:
	vector<int> in,dist;

	ConnectNodeInfo(int node_num){
		graph.resize(node_num);
		in.resize(node_num,0);
		dist.resize(node_num,0);
	}
	void AddConnection(ll u,ll v,ll w){
		graph[u].emplace_back(v,w);
		graph[v].emplace_back(u,w);
	}
	void AddConnection2(ll u,ll v,ll w){
		graph[u].emplace_back(v,w);
	}
	vector<pair<ll,ll>>& operator[](ll index){
		return graph[index];
	}
	size_t size(){return graph.size();}

	int dfs(set<int>& visit,int from,int len){
		int new_len = len;
		dist[from] = new_len;

		for(int i=0;i<graph[from].size();i++){
			auto res = visit.emplace(graph[from][i].first);
			if(!res.second){
				out(-1);
				exit(0);
			}
			if(dist[*res.first]>dist[from]+1){
				continue;
			}
			new_len = max(new_len,dfs(visit,*res.first,len+1));
			visit.erase(*res.first);
		}
		return new_len;
	}
	bool empty(){
		for(auto& x:graph){
			if(!x.empty()) return false;
		}
		return true;
	}
};

template<typename T>
bool chmax(T& a,T b){if(a<b){a=b;return true;}return false;}

int main(){
	cin.tie(0);
	ios::sync_with_stdio(false);

	int N=in();
	for(int i=0,n=0;i<N;i++){
		for(int j=i+1;j<N;j++){
			mindex[make_pair(i,j)] = n++;
		}
	}

	ConnectNodeInfo connect(mindex.size());
	vector<vector<int>> M(N,vector<int>(N-1));
	REP(i,N){
		REP(j,N-1){
			M[i][j]=in()-1;
		}
	}
	REP(i,N){
		REP(j,N-2){
			int a=i,b=M[i][j],c=M[i][j+1];
			if(b<a) swap(a,b);
			int pre = mindex[make_pair(a,b)];
			a=i;
			if(c<a) swap(a,c);
			int post = mindex[make_pair(a,c)];
			connect.AddConnection2(pre,post,1);
			connect.in[post]++;
		}
	}
	
	int max_len = -1;
	set<int> visit;
	vector<int> check_list;
	REP(i,mindex.size()){
		if(connect.in[i]==0){
			check_list.emplace_back(i);
		}
	}

	while(visit.size()<connect.size()){
		bool no_in = true;
		vector<int> erase_list;
		REP(i,check_list.size()){
			no_in = false;
			visit.emplace(check_list[i]);
			max_len = max(max_len,connect.dist[check_list[i]]);
			erase_list.emplace_back(check_list[i]);
			for(int j=0;j<connect[check_list[i]].size();j++){
				chmax(connect.dist[connect[check_list[i]][j].first],max(connect.dist[connect[check_list[i]][j].first],connect.dist[check_list[i]]+1));
			}
		}
		check_list.clear();
		for(auto& x:erase_list){
			for(int j=0;j<connect[x].size();j++){
				connect.in[connect[x][j].first]--;
				if(!connect.in[connect[x][j].first]){
					check_list.emplace_back(connect[x][j].first);
				}
			}
			//connect[x].clear();
		}
		if(no_in){
			out(-1);
			return 0;
		}
	}
	
	out(max_len+1);
	return 0;
}


Measured memory_bytes: 99712