CodeEff/ECCO huggingface dataset:
# Original solution
n = int(eval(input()))
g = [[-1, -1] for i in range(n*n)]
z = [0] * (n*n)

a = []
for _ in range(n):
    a.append([int(i) for i in input().split()])

for i in range(n):
    for j in range(n-2):
        p, q = (i, a[i][j]-1)
        r, s = (i, a[i][j+1]-1)
        r, s = (min(r, s), max(r ,s))
        if p < q:
            g[p*n+q][0] = r*n + s
        else:
            g[q*n+p][1] = r*n + s
        z[r*n+s] += 1

from collections import deque
qu = set([])
for i in range(n):
    p, q = (i, a[i][0]-1)
    p, q = (min(p, q), max(p ,q))
    if z[p*n+q] == 0:
        qu.add(p*n+q)

ans = 0
re = 0
qu = deque(qu)
while True:
    nqu = deque()
    while qu:
        s = qu.popleft()
        re += 1
        for t in g[s]:
            if t != -1:
                z[t] -= 1
                if z[t] == 0:
                    nqu.append(t)
    ans += 1    
    qu = nqu
    if not qu:
        break

if re == n*(n-1)//2:
    print(ans)
else:
    print((-1))

# Optimized solution
n = int(eval(input()))
g = [[-1, -1] for i in range(n*n)]
z = [0] * (n*n)

a = []
for _ in range(n):
    a.append([int(i) for i in input().split()])

for i in range(n):
    for j in range(n-2):
        p, q = (i, a[i][j]-1)
        r, s = (i, a[i][j+1]-1)
        r, s = (min(r, s), max(r ,s))
        if p < q:
            g[p*n+q][0] = r*n + s
        else:
            g[q*n+p][1] = r*n + s
        z[r*n+s] += 1

qu = set([])
for i in range(n):
    p, q = (i, a[i][0]-1)
    p, q = (min(p, q), max(p ,q))
    if z[p*n+q] == 0:
        qu.add(p*n+q)

ans = 0
re = 0
while True:
    nqu = []
    while qu:
        s = qu.pop()
        re += 1
        for t in g[s]:
            if t != -1:
                z[t] -= 1
                if z[t] == 0:
                    nqu.append(t)
    ans += 1    
    qu = nqu
    if not qu:
        break

if re == n*(n-1)//2:
    print(ans)
else:
    print((-1))
# Original solution
from collections import deque

N = int(eval(input()))
A = [list(map(int, input().split())) for _ in range(N)]

graph = [[] for _ in range(N * N)]
ins = [0] * (N * N)

for i, nodes in enumerate(A):
    for j1, j2 in zip(nodes[:-1], nodes[1:]):
        n1 = max(i, j1 - 1) * N + min(i, j1 - 1)
        n2 = max(i, j2 - 1) * N + min(i, j2 - 1)
        graph[n1].append(n2)
        ins[n2] += 1

visited = [False] * (N * N)
for i in range(N):
    visited[N * i + i] = True

que = deque()
for i, v in enumerate(ins):
    if v == 0:
        que.append((i, 1))

dist = [0] * (N * N)
while que:
    cur, d = que.popleft()
    
    visited[cur] = True
    dist[cur] = d
    for v in graph[cur]:
        if visited[v]:
            continue
            
        ins[v] -= 1
        if ins[v] == 0:
            que.append((v, d + 1))

print((max(dist) if all(visited) else -1))


# Optimized solution
from collections import deque

N = int(eval(input()))
X = [list(map(int, input().split())) for _ in range(N)]

graph = [[] for _ in range(N * N)]
ins = [0] * (N * N)

for i, nodes in enumerate(X):
    for j1, j2 in zip(nodes[:-1], nodes[1:]):
        n1 = max(i, j1 - 1) * N + min(i, j1 - 1)
        n2 = max(i, j2 - 1) * N + min(i, j2 - 1)
        graph[n1].append(n2)
        ins[n2] += 1

dist = [0] * (N * N)
visited = [False] * (N * N)
q = deque()
for i in range(N):
    visited[N * i + i] = True

for i, v in enumerate(ins):
    if v == 0:
        q.append((i, 1))

while q:
    u, d = q.popleft()
    visited[u] = True
    dist[u] = d

    for v in graph[u]:
        if visited[v]:
            continue
            
        ins[v] -= 1
        if ins[v] == 0:
            q.append((v, d + 1))
            
print((max(dist) if all(visited) else -1))
# Original solution
from collections import deque

N = int(eval(input()))
X = [list(map(int, input().split())) for _ in range(N)]

graph = [[] for _ in range(N * N)]
ins = [0] * (N * N)

for i, nodes in enumerate(X):
    for j1, j2 in zip(nodes[:-1], nodes[1:]):
        n1 = max(i, j1 - 1) * N + min(i, j1 - 1)
        n2 = max(i, j2 - 1) * N + min(i, j2 - 1)
        graph[n1].append(n2)
        ins[n2] += 1

dist = [0] * (N * N)
visited = [False] * (N * N)
q = deque()
for i in range(N):
    visited[N * i + i] = True

for i, v in enumerate(ins):
    if v == 0:
        q.append(i)
        visited[i] = True
        dist[i] = 1

while q:
    u = q.popleft()
    for v in graph[u]:
        if visited[v]:
            continue

        ins[v] -= 1
        if ins[v] == 0:
            visited[v] = True
            dist[v] = dist[u] + 1
            q.append(v)
            
print((max(dist) if all(visited) else -1))



# Optimized solution

from collections import deque

N = int(eval(input()))
X = [list(map(int, input().split())) for _ in range(N)]

graph = [[] for _ in range(N * N)]
inserted = [0] * (N * N)
for i, nodes in enumerate(X):
    for j1, j2 in zip(nodes[:-1], nodes[1:]):
        n1 = max(i, j1 - 1) * N + min(i, j1 - 1)
        n2 = max(i, j2 - 1) * N + min(i, j2 - 1)
        graph[n1].append(n2)
        inserted[n2] += 1

dist = [0] * (N * N)
visited = [False] * (N * N)
for i in range(N):
    visited[i * N + i] = True

q = deque()
for i, v in enumerate(inserted):
    if v == 0:
        q.append(i)
        visited[i] = True
        dist[i] = 1

while q:
    u = q.popleft()
    for v in graph[u]:
        if visited[v]:
            continue

        inserted[v] -= 1
        if inserted[v] == 0:
            visited[v] = True
            dist[v] = dist[u] + 1
            q.append(v)

print((max(dist) if all(visited) else -1))
# Original solution
# -*- coding: utf-8 -*-
"""
Created on Sun Sep  1 21:55:48 2019

@author: Yamazaki Kenichi
"""


N = int(eval(input()))
A = [list(map(int,input().split())) for i in range(N)]

T = [0 for i in range(N)]
today = [True for i in range(N)]
yesterday = [i for i in range(N)]

ans = 0
counta = 0
while counta < N:
    today = [True for i in range(N)]
    today_p = []
    for i in yesterday:
        if today[i]:
            vs = A[i][T[i]] - 1
            if A[vs][T[vs]] == i + 1 and today[vs]:
                T[i] += 1
                T[vs] += 1
                if T[i] == N - 1:
                    T[i] = 0
                    counta += 1
                if T[vs] == N - 1:
                    T[vs] = 0 
                    counta += 1
                today[i], today[vs] = False, False
                today_p.extend([i,vs])
    yesterday = today_p
#        print(i,vs,today,T)
    if len(today_p) == 0:
        ans = -1
        break
    ans += 1
print(ans)

# Optimized solution
# -*- coding: utf-8 -*-
"""
Created on Sun Sep  1 21:55:48 2019

@author: Yamazaki Kenichi
"""


N = int(eval(input()))
A = [list(map(int,input().split())) for i in range(N)]

T = [0 for i in range(N)]
today = [True for i in range(N)]
yesterday = [i for i in range(N)]

ans = 0
counta = 0
while counta < N:
    today = set([])
    today_p = []
    for i in yesterday:
        if not i in today:
            vs = A[i][T[i]] - 1
            if A[vs][T[vs]] == i + 1 and not vs in today:
                T[i] += 1
                T[vs] += 1
                if T[i] == N - 1:
                    T[i] = 0
                    counta += 1
                if T[vs] == N - 1:
                    T[vs] = 0 
                    counta += 1
                today.add(i)
                today.add(vs)
                today_p.extend([i,vs])
    yesterday = today_p
#        print(i,vs,today,T)
    if len(today_p) == 0:
        ans = -1
        break
    ans += 1
print(ans)
# Original solution
N = int(eval(input()))

# 初期化
G = [None] * (10 ** 6 + 1)  # グラフ
for i in range(10 ** 6 + 1):
    G[i] = set()
U = [None] * (10 ** 6 + 1)  # 入次数
D = [0] * (10 ** 6 + 1)  # 根からの距離


# 変換用
def x(i, j):
    return j + 1000 * i


# グラフを構築
for i in range(1, N + 1):
    A = list(map(int, input().split()))
    for j in range(N - 2):
        fv1, fv2 = min(i, A[j]), max(i, A[j])
        tv1, tv2 = min(i, A[j + 1]), max(i, A[j + 1])
        G[x(fv1, fv2)].add(x(tv1, tv2))
        U[x(fv1, fv2)] = 0
        U[x(tv1, tv2)] = 0


# 入次数をカウント
for i in range(10 ** 6 + 1):
    for v in G[i]:
        U[v] += 1

        
# トポロジカルソート
U_zero_nodes = []
for i in range(10 ** 6 + 1):
    if U[i] is None:
        continue

    if U[i] == 0:
        U_zero_nodes.append(i)


topological_order = []
while U_zero_nodes:
    n = U_zero_nodes.pop()
    topological_order.append(n)

    for v in G[n]:
        U[v] -= 1
        if U[v] == 0:
            U_zero_nodes.append(v)


# 不可能判定
if len(topological_order) != N * (N - 1) // 2:
    print((-1))
    exit()


# 最長経路を計算
for t_n in topological_order:
    for v in G[t_n]:
        D[v] = max(D[v], D[t_n] + 1)
print((max(D) + 1))


# Optimized solution
N = int(eval(input()))

# 初期化
G = [[] for i in range(10 ** 6 + 1)]  # グラフ
U = [None] * (10 ** 6 + 1)  # 入次数
D = [0] * (10 ** 6 + 1)  # 根からの距離


# 変換用
def x(i, j):
    return j + 1000 * i


# グラフを構築
for i in range(1, N + 1):
    A = list(map(int, input().split()))
    for j in range(N - 2):
        fv1, fv2 = min(i, A[j]), max(i, A[j])
        tv1, tv2 = min(i, A[j + 1]), max(i, A[j + 1])
        G[x(fv1, fv2)].append(x(tv1, tv2))
        U[x(fv1, fv2)] = 0
        U[x(tv1, tv2)] = 0


# 入次数をカウント
for i in range(10 ** 6 + 1):
    for v in G[i]:
        U[v] += 1

# トポロジカルソート
U_zero_nodes = []
for i in range(10 ** 6 + 1):
    if U[i] is None:
        continue

    if U[i] == 0:
        U_zero_nodes.append(i)


topological_order = []
while U_zero_nodes:
    n = U_zero_nodes.pop()
    topological_order.append(n)

    for v in G[n]:
        U[v] -= 1
        if U[v] == 0:
            U_zero_nodes.append(v)


# 不可能判定
if len(topological_order) != N * (N - 1) // 2:
    print((-1))
    exit()


# 最長経路を計算
for t_n in topological_order:
    for v in G[t_n]:
        D[v] = max(D[v], D[t_n] + 1)
print((max(D) + 1))
# Original solution
N = int(eval(input()))

# 初期化
G = [[] for i in range(10 ** 6 + 1)]  # グラフ
U = [None] * (10 ** 6 + 1)  # 入次数
D = [0] * (10 ** 6 + 1)  # 根からの距離


# 変換用
def x(i, j):
    return j + 1000 * i


# グラフを構築
for i in range(1, N + 1):
    A = list(map(int, input().split()))
    for j in range(N - 2):
        fv1, fv2 = min(i, A[j]), max(i, A[j])
        tv1, tv2 = min(i, A[j + 1]), max(i, A[j + 1])
        G[x(fv1, fv2)].append(x(tv1, tv2))
        U[x(fv1, fv2)] = 0
        U[x(tv1, tv2)] = 0


# 入次数をカウント
for i in range(10 ** 6 + 1):
    for v in G[i]:
        U[v] += 1

# トポロジカルソート
U_zero_nodes = []
for i in range(10 ** 6 + 1):
    if U[i] is None:
        continue

    if U[i] == 0:
        U_zero_nodes.append(i)


topological_order = []
while U_zero_nodes:
    n = U_zero_nodes.pop()
    topological_order.append(n)

    for v in G[n]:
        U[v] -= 1
        if U[v] == 0:
            U_zero_nodes.append(v)


# 不可能判定
if len(topological_order) != N * (N - 1) // 2:
    print((-1))
    exit()


# 最長経路を計算
for t_n in topological_order:
    for v in G[t_n]:
        D[v] = max(D[v], D[t_n] + 1)
print((max(D) + 1))


# Optimized solution
N = int(eval(input()))
A = [list([int(x) - 1 for x in input().split()]) + [-1] for i in range(N)]

ans = 0
matched = 0
marker = [0] * N
que = list(range(N))

while matched < N * (N - 1) // 2:
    already_matched = set()
    no_matched = True
    next_que = []

    while que:
        player = que.pop()
        partner = A[player][marker[player]]

        if A[partner][marker[partner]] == player:
            if not ((player not in already_matched) and (partner not in already_matched)):
                continue

            matched += 1

            marker[player] += 1
            marker[partner] += 1

            already_matched.add(player)
            already_matched.add(partner)

            next_que.append(player)
            next_que.append(partner)

            no_matched = False

    ans += 1
    que = next_que[:]
    if no_matched:
        print((-1))
        break

else:
    print(ans)
# Original solution
N = int(eval(input()))
A = [list([int(x) - 1 for x in input().split()]) + [-1] for i in range(N)]

ans = 0
matched = 0
marker = [0] * N
que = list(range(N))

while matched < N * (N - 1) // 2:
    already_matched = set()
    no_matched = True
    next_que = []

    while que:
        player = que.pop()
        partner = A[player][marker[player]]

        if A[partner][marker[partner]] == player:
            if not ((player not in already_matched) and (partner not in already_matched)):
                continue

            matched += 1

            marker[player] += 1
            marker[partner] += 1

            already_matched.add(player)
            already_matched.add(partner)

            next_que.append(player)
            next_que.append(partner)

            no_matched = False

    ans += 1
    que = next_que[:]
    if no_matched:
        print((-1))
        break

else:
    print(ans)


# Optimized solution
N = int(eval(input()))
A = [list([int(x) - 1 for x in input().split()]) + [-1] for i in range(N)]

ans = 0
matched = 0
marker = [0] * N
que = list(range(N))

while matched < N * (N - 1) // 2:
    already_matched = set()
    next_que = []

    while que:
        player = que.pop()
        partner = A[player][marker[player]]

        if A[partner][marker[partner]] == player:
            if not ((player not in already_matched) and (partner not in already_matched)):
                continue

            matched += 1

            marker[player] += 1
            marker[partner] += 1

            already_matched.add(player)
            already_matched.add(partner)

            next_que.append(player)
            next_que.append(partner)

    if not next_que:
        print((-1))
        break

    ans += 1
    que = next_que[:]

else:
    print(ans)
# Original solution
N = int(eval(input()))
A = [list([int(x)-1 for x in input().split()]) for i in range(N)]
B = [0]*N
days = 0
games_amount = 0
while True:
    C = [0]*N
    for i in range(N):
        if C[i] == 0 and B[i] != N-1:
            b = A[i][B[i]]
            if C[b] == 1:
                continue
            if A[b][B[b]] == i:
                B[i] += 1
                B[b] += 1
                C[i], C[b] = 1, 1
    if sum(C) == 0:
        break
    days += 1
print((days if sum(B) == N*(N-1) else -1))

# Optimized solution
import time

start = time.time()

N = int(eval(input()))
A = [list([int(x)-1 for x in input().split()]) for i in range(N)]
B = [0]*N
days = 0
games_amount = 0

for i in range(N*(N-1)//2):
    games = 0
    played = set()
    for j in range(N):
        if len(A[j]) == 0 or j in played or A[j][0] in played:
            continue
        if A[A[j][0]][0] == j:
            t1 = A[j].pop(0)
            played.add(t1)
            played.add(A[t1].pop(0))
            games += 1
            games_amount += 1
    if games == 0:
        print((-1))
        exit(0)
    else:
        days += 1
    if games_amount == N*(N-1)//2:
        break
    if time.time() - start > 1.9:
        print((N*(N-1)//2))
        exit(0)
print(days)
# Original solution
import sys
input=sys.stdin.readline
from collections import deque

def main():
    N = int(eval(input()))
    Q = [deque(list(map(int, input().split()))) for _ in range(N)]
    games = N*(N-1)//2

    days = 0
    nxt = [i for i in range(N)] # 翌日に対戦相手を更新する選手のリスト
    opp = [0]*N # 選手毎の、次の対戦相手のリスト
    while 1:
        days += 1
        for i in nxt:
            opp[i] = Q[i].popleft() - 1 if Q[i] else -1

        gamed = [0]*N # 選手がその日に試合済みかどうか
        tmp = [] # 次の日の更新のため、試合をした選手をメモ
        for i in nxt:
            if gamed[i] == 0 and opp[i] >= 0 and i == opp[opp[i]]:
#                print("game:", i+1, opp[i]+1, days)
                tmp.append(i)
                tmp.append(opp[i])
                gamed[i] = gamed[opp[i]] = 1
                games -= 1
        if games == 0:
            break
        elif not tmp:
            print((-1))
            return
        nxt = tmp
    print(days)

if __name__ == '__main__':
    main()

# Optimized solution
import sys
input=sys.stdin.readline
from collections import deque

def main():
    N = int(eval(input()))
    Q = [deque(list(map(int, input().split()))) for _ in range(N)]
    games = N*(N-1)//2

    days = 0
    nxt = [i for i in range(N)] # 翌日に対戦相手を更新する選手のリスト
    opp = [0]*N # 選手毎の、次の対戦相手のリスト
    while 1:
        days += 1
        for i in nxt:
            opp[i] = Q[i].popleft() - 1 if Q[i] else -1

        tmp = set() # 次の日の更新のため、試合をした選手をメモ
        for i in nxt:
            if i not in tmp and i == opp[opp[i]]:
#                print("game:", i+1, opp[i]+1, days)
                tmp.add(i)
                tmp.add(opp[i])
                games -= 1
        if games == 0:
            break
        elif not tmp:
            print((-1))
            return
        nxt = tmp
    print(days)

if __name__ == '__main__':
    main()
# Original solution
# ABC139E - League
from collections import deque


def main():
    N, *A = list(map(int, open(0).read().split()))
    B = {}
    for i in range(N):
        x = i * (N - 1)
        B[i + 1] = deque(A[x : x + N - 1])
    ans, flg, matched = 0, 0, set()
    while B:
        for i in list(B.keys()):
            if i in B and i not in matched:
                x = B[i][0]
                if x in B and x not in matched and B[x][0] == i:
                    B[i].popleft(), B[x].popleft()
                    matched |= {i, x}
                    flg = 1
                    if not B[i]:
                        del B[i]
                    if not B[x]:
                        del B[x]
        if flg:
            ans += 1
            flg, matched = 0, set()
        else:
            print((-1))
            return
    print(ans)


if __name__ == "__main__":
    main()

# Optimized solution
# ABC139E - League
from collections import deque


def main():
    N, *A = list(map(int, open(0).read().split()))
    B = {}
    for i in range(N):
        x = i * (N - 1)
        B[i + 1] = deque(A[x : x + N - 1])
    ans, cnt, matched = 0, 0, set()
    q = [i for i in range(1, N + 1)]
    while q:
        ans += 1
        next_q = []
        for i in q:
            if i in B and i not in matched:
                x = B[i][0]
                if x in B and x not in matched and B[x][0] == i:
                    B[i].popleft(), B[x].popleft()
                    matched |= {i, x}
                    cnt += 1
                    if not B[i]:
                        del B[i]
                    else:
                        next_q += [i]
                    if not B[x]:
                        del B[x]
                    else:
                        next_q += [x]
        q = next_q
        matched = set()
    flg = cnt == N * (N - 1) // 2
    print((ans if flg else -1))


if __name__ == "__main__":
    main()
# Original solution
# ABC139E - League
from collections import deque


def main():
    N, *A = list(map(int, open(0).read().split()))
    B = {}
    for i in range(N):
        x = i * (N - 1)
        B[i + 1] = deque(A[x : x + N - 1])
    cnt, cur, days = 0, [0] * (N + 1), [0] * (N + 1)
    q = deque(list(range(1, N + 1)))
    while q:
        x = q.popleft()
        if not B[x]:  # player x has finished all games
            continue
        y = B[x].popleft()
        if cur[y] == x:  # player y's next game is against x and vice versa
            cnt += 1
            days[x] = days[y] = max(days[x], days[y]) + 1
            cur[x], cur[y] = 0, 0
            q.append(x), q.append(y)
        else:  # the opponent will do another game before playing against x
            cur[x] = y
    flg = cnt == N * (N - 1) // 2  # finished all scheduled games or not
    print((max(days) if flg else -1))


if __name__ == "__main__":
    main()

# Optimized solution
# ABC139E - League
from collections import deque


def main():
    N = int(eval(input()))
    A = [0] + list(deque(list(map(int, input().split()))) for _ in range(N))
    cnt, cur, days = 0, [0] * (N + 1), [0] * (N + 1)
    q = deque(list(range(1, N + 1)))
    while q:
        x = q.popleft()
        if not A[x]:  # player x has finished all games
            continue
        y = A[x].popleft()  # the opponent of x
        if cur[y] == x:  # player y's next game is against x and vice versa
            cnt += 1
            days[x] = days[y] = max(days[x], days[y]) + 1  # day of playing the game
            cur[x], cur[y] = 0, 0  # no next game is currently planned
            q.append(x), q.append(y)
        else:  # the opponent will do another game before playing against x
            cur[x] = y
    flg = cnt == N * (N - 1) // 2  # finished all scheduled games or not
    print((max(days) if flg else -1))


if __name__ == "__main__":
    main()
# Original solution
import sys
import collections
import copy

input = sys.stdin.readline


def main():
    N = int(eval(input()))
    A = [collections.deque([int(x) for x in input().split()]) for _ in range(N)]

    day = 0
    c = 0
    nxt = [A[x][0] for x in range(N)]
    for i in range(N):
        A[i].popleft()

    while c != N * (N - 1):
        day += 1

        nxt2 = copy.copy(nxt)
        tmp = set()
        for i in set(nxt):
            if i == -1 or i in tmp:
                continue
            if i == nxt[nxt[i - 1] - 1]:
                if A[i - 1]:
                    nxt2[i - 1] = A[i - 1].popleft()
                else:
                    nxt2[i - 1] = -1
                if A[nxt[i - 1] - 1]:
                    nxt2[nxt[i - 1] - 1] = A[nxt[i - 1] - 1].popleft()
                else:
                    nxt2[nxt[i - 1] - 1] = -1
                tmp.add(i)
                tmp.add(nxt[i - 1])
                c += 2
        if not tmp:
            print((-1))
            return

        nxt = copy.copy(nxt2)

    print(day)


if __name__ == '__main__':
    main()


# Optimized solution
import sys
import collections
import copy

input = sys.stdin.readline


def main():
    N = int(eval(input()))
    A = [collections.deque([int(x) for x in input().split()]) for _ in range(N)]

    day = 0
    c = 0
    nxt = [x for x in range(N)]
    oppo = [0] * N

    while c != N * (N - 1):
        day += 1

        for i in nxt:
            oppo[i] = A[i].popleft() if A[i] else -1

        tmp = set()
        for i in nxt:
            if i == -1 or i in tmp:
                continue
            if i == oppo[oppo[i] - 1] - 1:
                tmp.add(i)
                tmp.add(oppo[i] - 1)
                c += 2
        if not tmp:
            print((-1))
            return

        nxt = tmp

    print(day)


if __name__ == '__main__':
    main()
# Original solution
import sys
import collections
import copy

input = sys.stdin.readline


def main():
    N = int(eval(input()))
    A = [collections.deque([int(x) for x in input().split()]) for _ in range(N)]

    day = 0
    c = 0
    nxt = [x for x in range(N)]
    oppo = [0] * N

    while c != N * (N - 1):
        day += 1

        for i in nxt:
            oppo[i] = A[i].popleft() if A[i] else -1

        tmp = set()
        for i in nxt:
            if i == -1 or i in tmp:
                continue
            if i == oppo[oppo[i] - 1] - 1:
                tmp.add(i)
                tmp.add(oppo[i] - 1)
                c += 2
        if not tmp:
            print((-1))
            return

        nxt = tmp

    print(day)


if __name__ == '__main__':
    main()


# Optimized solution
import sys
import collections
from collections import defaultdict

sys.setrecursionlimit(10 ** 8)

input = sys.stdin.readline


def main():
    N = int(eval(input()))
    A = [[int(x) for x in input().split()] for _ in range(N)]

    q = [collections.deque() for j in range(N)]

    for i, a in enumerate(A):
        for aa in a:
            q[i].append(aa)

    ans = 0

    current = defaultdict(int)
    for i, v in enumerate(q):
        current[i + 1] = v[0]

    while True:
        v = set()
        for k in list(current.keys()):
            if k == q[current[k] - 1][0]:
                v.add(k)
                v.add(current[k])

        current = defaultdict(int)

        if len(v) == 0:
            break

        for vv in v:
            q[vv - 1].popleft()
            if len(q[vv - 1]):
                current[vv] = q[vv - 1][0]

        ans += 1

    # 全て空なら
    size = 0
    for i in range(N):
        size += len(q[i])

    if size == 0:
        print(ans)
    else:
        print((-1))


if __name__ == '__main__':
    main()