### BUGGY CODE ###

class DirectedGraph:
    def __init__(self, adj):
        self.n = len(adj)
        self.adj = adj
        self.is_asyclic = False
        self.max_path_len = None

    def topological_sort(self):
        indegree = [0] * self.n
        for i, vs in enumerate(self.adj):
            for dest in vs:
                indegree[dest] += 1
        zero_v = []
        for v, indeg in enumerate(indegree):
            if indeg == 0:
                zero_v.append(v)
        max_path_len = 1
        tp_sorted = []
        to_be_added = []
        while True:
            while zero_v:
                v = zero_v.pop()
                tp_sorted.append(v)
                for dest in self.adj[v]:
                    indegree[dest] -= 1
                    if indegree[dest] == 0:
                        to_be_added.append(dest)
            if len(to_be_added) > 0:
                zero_v += to_be_added
                to_be_added = []
                max_path_len += 1
            else:
                break
        if len(tp_sorted) == self.n:
            self.is_asyclic = True
            self.max_path_len = max_path_len
            return tp_sorted
        else:
            self.is_asyclic = False
            return None

if __name__ == "__main__":
    n = int(input())
    dic = {}
    itr = 0
    for i in range(n):
        for j in range(i+1, n):
            dic[i*n + j] = itr
            itr += 1
    edge = [[] for _ in range(n * (n-1) // 2)]
    for i in range(n):
        a = [int(item) - 1 for item in input().split()]
        for j1, j2 in zip(a, a[1:]):
            if i < j1:
                u = i * n + j1 
            else:
                u = j1 * n + i 
            if i < j2:
                v = i * n + j2 
            else:
                v = j2 * n + i 
            edge[dic[u]].append(dic[v])

    DG = DirectedGraph(edge)
    tps = DG.topological_sort()

    if DG.is_asyclic:
        print(DG.max_path_len)
    else:
        print(-1)

### FIXED CODE ###

class DirectedGraph:
    def __init__(self, adj):
        self.n = len(adj)
        self.adj = adj
        self.is_asyclic = False
        self.max_path_len = None

    def topological_sort(self):
        indegree = [0] * self.n
        for i, vs in enumerate(self.adj):
            for dest in vs:
                indegree[dest] += 1
        zero_v = []
        for v, indeg in enumerate(indegree):
            if indeg == 0:
                zero_v.append(v)
        max_path_len = 1
        tp_sorted = []
        to_be_added = []
        while True:
            while zero_v:
                v = zero_v.pop()
                tp_sorted.append(v)
                for dest in self.adj[v]:
                    indegree[dest] -= 1
                    if indegree[dest] == 0:
                        to_be_added.append(dest)
            if len(to_be_added) > 0:
                zero_v += to_be_added
                to_be_added = []
                max_path_len += 1
            else:
                break
        if len(tp_sorted) == self.n:
            self.is_asyclic = True
            self.max_path_len = max_path_len
            return tp_sorted
        else:
            self.is_asyclic = False
            return None

if __name__ == "__main__":
    n = int(input())
    dic = {}
    itr = 0
    for i in range(n):
        for j in range(i+1, n):
            dic[i*n + j] = itr
            itr += 1
    edge = [[] for _ in range(n * (n-1) // 2)]
    for i in range(n):
        a = [int(item) - 1 for item in input().split()]
        for j1, j2 in zip(a, a[1:]):
            if i < j1:
                u = i * n + j1 
            else:
                u = j1 * n + i 
            if i < j2:
                v = i * n + j2 
            else:
                v = j2 * n + i 
            edge[dic[u]].append(dic[v])

    DG = DirectedGraph(edge)
    tps = DG.topological_sort()

    if DG.is_asyclic:
        print(DG.max_path_len)
    else:
        print(-1)