#include<iostream>
#include<iomanip>
#include<vector>
#include<string>
#include<algorithm>
#include<cmath>
#include<functional>
#include<map>
#include<cstdlib>
#include<complex>
#include<numeric>
#include<set>
#include<deque>
#include<queue>

using namespace std;
using Int = long long;
Int INF = 1LL << 60;
const Int MOD = 1000000000 + 7;

#include <cassert>
#include <cstdio>
#include <cmath>
#include <iostream>
#include <vector>
#include <queue>

using namespace std;
using Int = long long;

class Topological_sort {
private:
	Int V;
	vector<vector<Int>> edges;
	vector<Int> used;

public:
	Topological_sort(Int n) :V(n), edges(n), used(n) {}
	Topological_sort(vector<vector<Int>>& edges) :V(edges.size()), used(edges.size()) { this->edges = edges; }

	void add_edge(Int from, Int to) { edges[from].emplace_back(to); }

	vector<Int> build() {

		vector<Int> res, in(V);
		for (Int i = 0; i < V; i++) for (const auto& e : edges[i]) in[e]++;

		res.reserve(V);
		queue<Int> que;
		for (Int i = 0; i < V; i++) {
			if (in[i] == 0 && !used[i]) {
				used[i] = 1;
				que.emplace(i);
			}
		}
		while (!que.empty()) {
			Int now = que.front();
			//DMP(now, in);
			que.pop();
			res.emplace_back(now);
			for (const auto& e : edges[now]) {
				in[e]--;
				if (in[e] == 0) {
					if (used[e]) {
						vector<Int> a{ 0 };
						return  a;// unable to sort
					}
					used[e] = used[now] + 1;
					que.emplace(e);
				}
			}
		}

		return res;
	}

	Int longest_path() {
		if (none_of(used.begin(), used.end(), [](Int u) { return u > 0; })) build();
		return *max_element(used.begin(), used.end()) - 1;
	}

};

template <class T>
ostream& operator<<(ostream& os, const vector<T>& vec) {
	for (const auto& e : vec) os << e << (&e == &vec.back() ? "\n" : " ");
	return os;
}
template <class T>
ostream& operator<<(ostream& os, const set<T>& st) {
	for (const auto& e : st) os << e << " ";
	return os;
}
template <class T1, class T2>
ostream& operator<<(ostream& os, const pair<T1, T2>& p) {
	os << "(" << p.first << "," << p.second << ")";
	return os;
}
template <class T1, class T2>
ostream& operator<<(ostream& os, const map<T1, T2>& mp) {
	for (const auto& e : mp) os << e << " ";
	return os;
}

#ifdef _DEBUG
template <class T>
void dump(const char* str, T&& h) { cerr << str << " = " << h << "\n"; };
template <class Head, class... Tail>
void dump(const char* str, Head&& h, Tail&&... t) {
	while (*str != ',') cerr << *str++; cerr << " = " << h << "\n";
	dump(str + (*(str + 1) == ' ' ? 2 : 1), t...);
}
#define DMP(...) dump(#__VA_ARGS__, __VA_ARGS__)
#else 
#define DMP(...) ((void)0)
#endif


int main() {

	cin.tie(nullptr);
	ios::sync_with_stdio(false);

	Int N;
	cin >> N;

	vector<vector<Int>> A(N, vector<Int>(N-1));
	for (Int i = 0; i < N; i++) {
		for (Int j = 0; j < N-1; j++) {
			cin >> A[i][j];
			A[i][j]--;
		}
	}

	vector<vector<Int>> Edge(N * N);
	Int from, to;
	for (Int i = 0; i < N; i++) {
		for (Int j = 0; j < N-2; j++) {
			from = min(i, A[i][j]) * N + max(i, A[i][j]);
			to = min(i, A[i][j + 1]) * N + max(i, A[i][j + 1]);

			Edge[from].push_back(to);
		}
	}

	Topological_sort f(Edge);
	auto ans = f.build();

	DMP(ans);

	if (ans.size()!=N*N) {
		cout << -1 << "\n";
	}
	else {
		cout << f.longest_path()+1<< "\n";
	}

}


Measured memory_bytes: 111488