#include <bits/stdc++.h>
#define loop(n) for (int ngtkana_is_genius = 0; ngtkana_is_genius < int(n); ngtkana_is_genius++)
#define rep(i, begin, end) for(int i = int(begin); i < int(end); i++)
#define lint long long
auto cmn = [](auto& a, auto b){if (a > b) {a = b; return true;} return false;};
auto cmx = [](auto& a, auto b){if (a < b) {a = b; return true;} return false;};
void debug_impl() { std::cerr << std::endl; }
template <typename Head, typename... Tail>
void debug_impl(Head head, Tail... tail){
  std::cerr << " " << head;
  debug_impl(tail...);
}
#define debug(...) std::cerr << std::boolalpha << "[" << #__VA_ARGS__ << "]:";\
  debug_impl(__VA_ARGS__);\
  std::cerr << std::noboolalpha;

class topological_sort {
    int                           n;
    std::vector<std::vector<int>> graph;
    std::vector<int>              ckd;
    std::vector<int>              sorted;

    bool dfs (int crr) {
      if (ckd.at(crr) == 1) return true;
      if (ckd.at(crr) == 2) return false;
      bool ret = false;
      ckd.at(crr) = 1;
      for (int nxt : graph.at(crr)) {
        ret |= dfs(nxt);
      } 
      ckd.at(crr) = 2;
      sorted.push_back(crr);
      return ret;
    }

  public:
    topological_sort(int n):
      n(n), graph(n), ckd(n, 0), sorted{}{}

    void insert(int i, int j) {
      graph.at(i).emplace_back(j);
    }

    bool build() {
      for (auto i = 0; i < n; i++) {
        if (ckd.at(i) == 0 && dfs(i)) return true;
      }
      std::reverse(sorted.begin(), sorted.end());
      return false;
    }

    auto result() const { return sorted; }
};

template <typename T>
auto make_vector_impl(size_t sz, T t) {return std::vector<T>(sz, t);}

template <size_t N, typename T, typename U, std::enable_if_t<N == 1, std::nullptr_t> = nullptr>
auto make_vector(size_t sz, U u) {return make_vector_impl(sz, T(u));}

template <size_t N, typename T, std::enable_if_t<N == 1, std::nullptr_t> = nullptr>
auto make_vector(size_t sz) {return std::vector<T>(sz);}

template <size_t N, typename T, typename... Args, std::enable_if_t<N != 1, std::nullptr_t> = nullptr>
auto make_vector(size_t a, Args... args) {return make_vector_impl(a, make_vector<N - 1, T>(args...));}

template <typename T, typename Size_t>
auto& at(T& t, Size_t i) {return t.at(i);}

template <typename T, typename Size_t, typename... Args>
auto& at(T& t, Size_t i, Args... args) {return at(t.at(i), args...);}

template <typename T, typename U>
std::ostream& operator<< (std::ostream& os, const std::pair<T, U>& pair){
  return os << "(" << pair.first << "," << pair.second << ")";
}

template <typename T, typename U>
std::istream& operator>> (std::iostream& is, std::pair<T, U>& pair) {
  return is >> pair.first >> pair.second;
}

template <typename T>
std::istream& operator>> (std::istream& is, std::vector<T>& v)
{
  for (auto & x : v) is >> x;
  return is;
}

template <typename T>
std::ostream& operator<< (std::ostream& os, const std::vector<T>& v)
{
  auto n = v.size();
  os << "{";
  for (size_t i = 0; i < n; i++)
    os << (i > 0 ? "," : "") << v[i];
  return os << "}";
}

int main() {
  std::cin.tie(0); std::cin.sync_with_stdio(false);
  int n; std::cin >> n;
  auto N = n * (n - 1) / 2;
  std::vector<std::pair<int, int>> table(N);
  auto encode = [&] (int i, int j) {
    if (i < j) std::swap(i, j);
    return i * (i - 1) / 2 + j;
  };
  auto decode = [&] (int x) { return table.at(x); };
  auto list   = make_vector<2, int>(n, n - 1, -1);
  rep(i, 0, n) {
    rep(j, 0, n) {
      if (i == j) continue;
      auto code = encode(i, j);
      if (i > j) table.at(code) = {i, j};
      int x; std::cin >> x;
      x--;
      at(list, i, j - (i < j)) = encode(i, x);
    }
  }
  auto rev = make_vector<2, int>(N, 0);
  auto tps = topological_sort(N);
  for (auto const& v : list) {
    rep(j, 0, n - 2) {
      tps.insert(v.at(j), v.at(j + 1));
      rev.at(v.at(j + 1)).push_back(v.at(j));
    }
  }
  auto err = [&] {
    std::cout << -1 << std::endl;
    exit(0);
  };
  if (tps.build()) err();
  auto sorted = tps.result();
  // debug(sorted); 
  std::vector<int> dp(N, 0);
  for (auto x : sorted) {
    for (auto prv : rev.at(x)) {
      cmx(dp.at(x), dp.at(prv) + 1);
    }
  }
  auto ret = *max_element(dp.begin(), dp.end()) + 1;
  std::cout << ret << std::endl;
  return 0;
}


Measured memory_bytes: 70772