#include <iostream>
#include <vector>
#include <algorithm>
#include <assert.h>


struct match_node{
    int32_t num_parent = 0;
    std::vector<match_node*> child_ptrs;
    //std::vector<match_node*> child_ptrs(2, nullptr);
    int32_t idx = 0;
    bool np_list_reged = false;
};


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

    // 1 Match / day / person
    // Ai1, Ai2, .... , AiN-1
    // Node connection graph N * N
    // for each non-parent nodes
    //  check child, remove p-c edge, if no p-c edge: push to non-parent list 
    //  pop from non-parent list
    // Num Children for each node <= 2, ... O(2N)
    int32_t num_match = N * (N - 1) / 2;
    std::vector<match_node> match_list(num_match);
    std::vector<match_node*> non_parent_list;

    std::vector<int32_t> idx_offsets(N, 0);
    int32_t idx_offset = -1;
    idx_offsets[0] = idx_offset;
    for(int32_t k = 1; k < N; k++){
        idx_offset += N - k;
        idx_offsets[k] = idx_offset;
    }

    for(int32_t i = 1; i <= N; i++){
        match_node* prev_A = nullptr;
        for(int32_t j = 1; j <= N-1; j++){
            int32_t A;
            std::cin >> A;
            assert(i != A);
            int32_t idx = idx_offsets[std::min(i, A) - 1] + std::max(i, A) - std::min(i, A); 
            //std::cout << "i:A:idx = " << i << ":" << A << ":" << idx << std::endl;
            auto iA_node = &(match_list[idx]);
            if(prev_A != nullptr){
                prev_A->child_ptrs.push_back(iA_node);
                iA_node->num_parent++;
            }
            else if(iA_node->num_parent == 0 && !iA_node->np_list_reged){
                // just a candidate. This node could be the child later.
                iA_node->np_list_reged = true;
                non_parent_list.push_back(iA_node);

            }
            iA_node->idx = idx;
            //std::cout << "idx,p_cnt = " << idx << ":" << iA_node->num_parent << std::endl;
            prev_A = iA_node;
        }
    }
    //std::cout << "np_list_length :" << non_parent_list.size() << std::endl;
    // clean-up np_list. Some member has parent.
    uint32_t prev_size = -1;
    while(prev_size != non_parent_list.size()){
        prev_size = non_parent_list.size();
        for(auto i = non_parent_list.begin(); i < non_parent_list.end(); i++){
            //std::cout << "np_list idx, parent_cnt:" << (*i)->idx << "," << (*i)->num_parent << std::endl;
            if((*i)->num_parent != 0){
                i = non_parent_list.erase(i);
            }
        }
    }


    int32_t day_cnt = 0;
    int32_t match_cnt = 0;
    std::vector<match_node*> next_non_parent_list;
    while(match_cnt < num_match){
        if(non_parent_list.empty()){
            day_cnt = -1;
            break;
        }
        for(auto i = non_parent_list.begin(); i < non_parent_list.end(); i++){
            //std::cout << "processing np_list_id :" << (*i)->idx << std::endl;
            for(auto child : (*i)->child_ptrs){
                child->num_parent--;
                //std::cout << "num childs parent :" << child->num_parent << std::endl;
                if(child->num_parent == 0){
                    next_non_parent_list.push_back(child);
                    //std::cout << "push_back new np :" << child->idx << std::endl;
                }
            }
            match_cnt++;
        }
        non_parent_list.erase(non_parent_list.begin(),non_parent_list.end());
        non_parent_list.swap(next_non_parent_list);
        day_cnt++;
        //std::cout << "end of a day ..." << std::endl;
    }
    std::cout << day_cnt;

    return 0;
}


Measured memory_bytes: 35328