### BUGGY CODE ###

import sys
sys.setrecursionlimit(10**6)

def dfs(v, graph):
    if visited[v]:
        if not calculated[v]: #visited and not calculated == loop
            return -1 
        return depth[v]
    visited[v] = True
    for e in graph[v]: # すべての辺をなめる
        res = dfs(e, graph) # 再帰
        if res == -1: 
            return -1 # ループを見つけたら-1を返す
        
        depth[v] = max(depth[v], res+1) #より深い経路を発見したか？
    calculated[v] = True 
    return depth[v]


if __name__ == '__main__':
    N = int(input())
    Ng = N*(N-1)//2
    graph = [[] for _ in range(Ng)]
    G_id = [[-1]*N for _ in range(N)]
    
    game_id = 0
    first_game_id = []
    for i in range(N):
        row = list(map(int, input().split()))
        for d, r in enumerate(row):
            if G_id[i][r-1] == -1: #新しい試合の組み合わせ
                G_id[i][r-1] = game_id 
                G_id[r-1][i] = game_id
                
                if d != 0: # 行が更新されているかのチェック
                    graph[before].append(game_id)
                else:
                    first_game_id.append(game_id)
                    
                before = game_id # idの更新・一つ記録
                game_id += 1
            else: # 既存の組み合わせ
                if d != 0: # 行が更新されているかのチェック
                    graph[before].append(G_id[i][r-1])
                else:
                    first_game_id.append(G_id[i][r-1])
                before = G_id[i][r-1] #現在の試合を記録
    
    depth = [1]*Ng # 頂点から出発したときの最長経路
    visited = [False]*Ng
    calculated = [False]*Ng
    flag = True
    ans = 1
    for i in first_game_id:
        res = dfs(i, graph)
        if res == -1:
            flag = False
        else:
            ans = max(ans, res)
    if flag:
        print(ans)
    else:
        print(-1)
    
    

### FIXED CODE ###

import sys
sys.setrecursionlimit(10**6)

def dfs(v, graph):
    if visited[v]:
        if not calculated[v]: #visited and not calculated == loop
            return -1 
        return depth[v]
    visited[v] = True
    for e in graph[v]: # すべての辺をなめる
        res = dfs(e, graph) # 再帰
        if res == -1: 
            return -1 # ループを見つけたら-1を返す
        
        depth[v] = max(depth[v], res+1) #より深い経路を発見したか？
    calculated[v] = True 
    return depth[v]


if __name__ == '__main__':
    N = int(input())
    Ng = N*(N-1)//2
    graph = [[] for _ in range(Ng)]
    G_id = [[-1]*N for _ in range(N)]
    
    game_id = 0
    for i in range(N):
        row = list(map(int, input().split()))
        for d, r in enumerate(row):
            if G_id[i][r-1] == -1: #新しい試合の組み合わせ
                G_id[i][r-1] = game_id 
                G_id[r-1][i] = game_id
                
                if d != 0: # 行が更新されているかのチェック
                    graph[before].append(game_id)
                
                before = game_id # idの更新・一つ記録
                game_id += 1
            else: # 既存の組み合わせ
                if d != 0: # 行が更新されているかのチェック
                    graph[before].append(G_id[i][r-1])
                before = G_id[i][r-1] #現在の試合を記録
    
    depth = [1]*Ng # 頂点から出発したときの最長経路
    visited = [False]*Ng
    calculated = [False]*Ng
    flag = True
    ans = 1
    for i in range(Ng):
        res = dfs(i, graph)
        if res == -1:
            flag = False
        else:
            ans = max(ans, res)
    if flag:
        print(ans)
    else:
        print(-1)