#include <algorithm>
#include <bits/stdc++.h>
#include <cstdint>
#include <iostream>
#include <iterator>
#include <vector>

// lib/util.hpp
#ifndef UTIL_HPP
#define UTIL_HPP


typedef ::std::int_fast64_t i64;
typedef ::std::uint_fast64_t u64;
typedef ::std::int_fast32_t i32;
typedef ::std::uint_fast32_t u32;

namespace tools {
  template <typename T>
  void read(::std::istream& is, ::std::vector<T>& vector, const typename ::std::vector<T>::size_type size) {
    vector.reserve(size);
    ::std::copy_n(::std::istream_iterator<T>(is), size, ::std::back_inserter(vector));
  }
  template <typename T>
  void read(::std::vector<T>& vector, const typename ::std::vector<T>::size_type size) {
    ::tools::read(::std::cin, vector, size);
  }

  template <typename T, ::std::size_t N>
  void read(::std::istream& is, ::std::array<T, N>& array) {
    ::std::copy_n(std::istream_iterator<T>(is), N, array.begin());
  }
  template <typename T, ::std::size_t N>
  void read(::std::array<T, N>& array) {
    ::tools::read(::std::cin, array);
  }
}

#endif

// main.cpp

namespace std {
  template <>
  struct hash<std::pair<i64, i64>> {
    typedef std::size_t result_type;
    typedef std::pair<i64, i64> argument_type;
    std::size_t operator()(const std::pair<i64, i64>& key) const {
      static const std::hash<i64> hasher = std::hash<i64>();
      return hasher((key.first << 32) | key.second);
    }
  };
}

int main() {
  i64 N;
  std::cin >> N;

  std::vector<std::pair<i64, i64>> nodes;
  nodes.reserve(N * (N - 1) / 2);
  for (i64 i = 0; i < N - 1; ++i) {
    for (i64 j = i + 1; j < N; ++j) {
      nodes.push_back(std::make_pair(i, j));
    }
  }

  std::unordered_map<std::pair<i64, i64>, std::vector<std::pair<i64, i64>>> edges;
  edges.reserve(nodes.size());
  for (const std::pair<i64, i64>& node : nodes) {
    edges.emplace(node, std::vector<std::pair<i64, i64>>());
  }

  for (i64 i = 0; i < N; ++i) {
    std::vector<i64> A_i;
    tools::read(A_i, N - 1);
    std::transform(A_i.begin(), A_i.end(), A_i.begin(), [](const i64& A_ij) { return A_ij - 1; });
    for (auto it = ++A_i.begin(), prev_it = A_i.begin(); it != A_i.end(); prev_it = it, ++it) {
      edges[std::make_pair(std::min(i, *prev_it), std::max(i, *prev_it))].push_back(std::make_pair(std::min(i, *it), std::max(i, *it)));
    }
  }

  std::unordered_map<std::pair<i64, i64>, i64> ranks;
  ranks.reserve(nodes.size());
  const i64 UNKNOWN = -1;
  for (const std::pair<i64, i64>& node : nodes) {
    ranks.emplace(node, UNKNOWN);
  }

  std::unordered_set<std::pair<i64, i64>> unvisited(nodes.begin(), nodes.end());
  std::function<i64(std::pair<i64, i64>)> dfs;
  dfs = [&](const std::pair<i64, i64>& from) {
    if (ranks[from] != UNKNOWN) {
      return ranks[from];
    }
    if (unvisited.erase(from) == 0) {
      throw std::runtime_error("Found cycle!");
    }
    i64 max = 0;
    for (const std::pair<i64, i64>& to : edges[from]) {
      max = std::max(max, dfs(to));
    }
    return ranks[from] = max + 1;
  };

  try {
    while (!unvisited.empty()) {
      dfs(*unvisited.begin());
    }
  } catch (const std::runtime_error&) {
    std::cout << -1 << std::endl;
    return 0;
  }

  i64 answer = 0;
  for (const std::pair<std::pair<i64, i64>, i64>& pair : ranks) {
    answer = std::max(answer, pair.second);
  }
  std::cout << answer << std::endl;
  return 0;
}

Measured memory_bytes: 123648