Buggy python submission (verdict: Time Limit Exceeded):
N = int(input())
A = []
for i in range(N):
  A.append(list(map(int, input().split())))
#試合にコードを割り当てる
#of[l] = 前の番号の競技者の「既に数え上げた試合の数」
#r = 相手
#l = じぶん
def code(l, r, of):
  if l > r:
      l, r = r, l
  return of[l] + r - l - 1
#オフセットを作る。重複の試合を取り除くため、
#1ならN - 1試合、2ならN - 2試合...という風にする
of = [0] * (N + 1)
for i in range(N):
  of[i + 1] = of[i] + N - i - 1
#print(of)
#試合の前後関係を持つグラフ
#たぶんDAGになっている。なってないなら試合組めないと思う
g = [[] for _ in range(N * (N - 1) // 2)]
for i in range(N):
  for j in range(N - 2):
      fcode = code(i, A[i][j] - 1, of)
      tcode = code(i, A[i][j + 1] - 1, of)
      g[fcode].append(tcode)
#print(g)
def sort_topologically(g):
  n = len(g)
  #ecはコードによる試合頂点の入次数を記録
  ec = [0] * n
  for i in range(n):
    for e in g[i]:
      ec[e] += 1
  #print(ec)
  #retは入次数0の頂点を順にとってきている
  ret = [0] * n
  q = 0
  for i in range(n):
    if ec[i] == 0:
      ret[q] = i
      q += 1
  #p = 参照中の入次数0の試合
  #q = 入次数0の頂点数
  #while文はp == qの時点で終わる
  #for文では、入次数0の頂点pから出る有向辺を除去する
  #その上で入次数0の頂点が増えればretへ追加
  #このretは確かにトポロジカル順序になる
  p = 0
  #print(ret)
  while p < q:
    for to in g[ret[p]]:
      ec[to] -= 1
      if ec[to] == 0:
        ret[q] = to
        q += 1
    p += 1
  #ソートが終わったなら全ての辺は除去済みのはずである
  #このグラフは一応連結しているはずなので閉路検知ができる
  for i in range(n):
    if ec[i] > 0:
      return None
  return ret

od = sort_topologically(g)
#print(od)
#Noneなら閉路を持つので試合構築不可能
if not od:
  print(-1)
else:
  #dp = トポロジカル順序を持つ順序集合の先頭からi番目までを見た際の最大パス長
  dp = [1] * (N * (N - 1) // 2)
  for i in range(N * (N - 1) // 2):
    for e in g[od[i]]:
      dp[e] = max(dp[e], dp[od[i]] + 1)
  #print(dp)
  print(max(dp))



Fixed submission:
N = int(input())
A = []
for i in range(N):
  A.append(list(map(int, input().split())))
#試合にコードを割り当てる
#of[l] = 前の番号の競技者の「既に数え上げた試合の数」
#r = 相手
#l = じぶん
def code(l, r, of):
  if l > r:
      l, r = r, l
  return of[l] + r - l - 1
#オフセットを作る。重複の試合を取り除くため、
#1ならN - 1試合、2ならN - 2試合...という風にする
of = [0] * (N + 1)
for i in range(N):
  of[i + 1] = of[i] + N - i - 1
#print(of)
#試合の前後関係を持つグラフ
#たぶんDAGになっている。なってないなら試合組めないと思う
g = [[] for _ in range(N * (N - 1) // 2)]
for i in range(N):
  for j in range(N - 2):
      fcode = code(i, A[i][j] - 1, of)
      tcode = code(i, A[i][j + 1] - 1, of)
      g[fcode].append(tcode)
#print(g)
def sort_topologically(g):
  n = len(g)
  #ecはコードによる試合頂点の入次数を記録
  ec = [0] * n
  for i in range(n):
    for e in g[i]:
      ec[e] += 1
  #print(ec)
  #retは入次数0の頂点を順にとってきている
  ret = [0] * n
  q = 0
  for i in range(n):
    if ec[i] == 0:
      ret[q] = i
      q += 1
  #p = 参照中の入次数0の試合
  #q = 入次数0の頂点数
  #while文はp == qの時点で終わる
  #for文では、入次数0の頂点pから出る有向辺を除去する
  #その上で入次数0の頂点が増えればretへ追加
  #このretは確かにトポロジカル順序になる
  p = 0
  #print(ret)
  while p < q:
    for to in g[ret[p]]:
      ec[to] -= 1
      if ec[to] == 0:
        ret[q] = to
        q += 1
    p += 1
  #ソートが終わったなら全ての辺は除去済みのはずである
  #このグラフは一応連結しているはずなので閉路検知ができる
  for i in range(n):
    if ec[i] > 0:
      return None
  return ret

od = sort_topologically(g)
#print(od)
#Noneなら閉路を持つので試合構築不可能
if not od:
  print(-1)
else:
  #dp = トポロジカル順序を持つ順序集合の先頭からi番目までを見た際の最大パス長
  dp = [1] * (N * (N - 1) // 2)
  for i in range(N * (N - 1) // 2):
    for e in g[od[i]]:
      dp[e] = max(dp[e], dp[od[i]] + 1)
  #print(dp)
  print(max(dp))

Buggy python submission (verdict: Time Limit Exceeded):
from collections import defaultdict as dd
from copy import deepcopy as dc
import time
st = time.time()
N = int(input())
e = dd(list)

matche = dd(list)

for i in range(1, N + 1):
  e[i] = list(map(int, input().split()))

for i in range(1, N + 1):
  for j in range(N - 2):
    if matche[(min(e[i][j], i), max(e[i][j], i))] != []:
      matche[(min(e[i][j], i), max(e[i][j], i))].append((min(i, e[i][j + 1]), max(i, e[i][j + 1])))
    else:
      matche[(min(e[i][j], i), max(e[i][j], i))].append((min(i, e[i][j + 1]), max(i, e[i][j + 1])))
    #print(i, j, matche)
#print(matche)
matchkey = dc(matche)
S = matchkey.keys()
visited = dd(int)
depth = 0
#print(S)
def dfs(s):
  if time.time() - st > 1.7:
    print(N * (N - 1) // 2)
  global visited
  global depth
  temp = 0
  #print(s)
  if matche[s] != []:
    for c in matche[s]:
      if visited[c] == 1:
        print(-1)
        #print(visited, c)
        exit(0)
      else:
        depth += 1
        visited[c] = 1
        #print(depth)
        temp = max(dfs(c), temp)
        depth -= 1
        visited[c] = 0
  else:
    return depth
  return temp
temp = 0
for s in S:
  temp = max(dfs(s), temp)
print(temp + 1)

Fixed submission:
N = int(input())
A = []
for i in range(N):
  A.append(list(map(int, input().split())))
#試合にコードを割り当てる
#of[l] = 前の番号の競技者の「既に数え上げた試合の数」
#r = 相手
#l = じぶん
def code(l, r, of):
  if l > r:
      l, r = r, l
  return of[l] + r - l - 1
#オフセットを作る。重複の試合を取り除くため、
#1ならN - 1試合、2ならN - 2試合...という風にする
of = [0] * (N + 1)
for i in range(N):
  of[i + 1] = of[i] + N - i - 1
#print(of)
#試合の前後関係を持つグラフ
#たぶんDAGになっている。なってないなら試合組めないと思う
g = [[] for _ in range(N * (N - 1) // 2)]
for i in range(N):
  for j in range(N - 2):
      fcode = code(i, A[i][j] - 1, of)
      tcode = code(i, A[i][j + 1] - 1, of)
      g[fcode].append(tcode)
#print(g)
def sort_topologically(g):
  n = len(g)
  #ecはコードによる試合頂点の入次数を記録
  ec = [0] * n
  for i in range(n):
    for e in g[i]:
      ec[e] += 1
  #print(ec)
  #retは入次数0の頂点を順にとってきている
  ret = [0] * n
  q = 0
  for i in range(n):
    if ec[i] == 0:
      ret[q] = i
      q += 1
  #p = 参照中の入次数0の試合
  #q = 入次数0の頂点数
  #while文はp == qの時点で終わる
  #for文では、入次数0の頂点pから出る有向辺を除去する
  #その上で入次数0の頂点が増えればretへ追加
  #このretは確かにトポロジカル順序になる
  p = 0
  #print(ret)
  while p < q:
    for to in g[ret[p]]:
      ec[to] -= 1
      if ec[to] == 0:
        ret[q] = to
        q += 1
    p += 1
  #ソートが終わったなら全ての辺は除去済みのはずである
  #このグラフは一応連結しているはずなので閉路検知ができる
  for i in range(n):
    if ec[i] > 0:
      return None
  return ret

od = sort_topologically(g)
#print(od)
#Noneなら閉路を持つので試合構築不可能
if not od:
  print(-1)
else:
  #dp = トポロジカル順序を持つ順序集合の先頭からi番目までを見た際の最大パス長
  dp = [1] * (N * (N - 1) // 2)
  for i in range(N * (N - 1) // 2):
    for e in g[od[i]]:
      dp[e] = max(dp[e], dp[od[i]] + 1)
  #print(dp)
  print(max(dp))

Buggy python submission (verdict: Time Limit Exceeded):
from collections import defaultdict as dd
from copy import deepcopy as dc
import time
st = time.time()
N = int(input())
e = dd(list)

matche = dd(list)

for i in range(1, N + 1):
  e[i] = list(map(int, input().split()))

for i in range(1, N + 1):
  for j in range(N - 2):
    if matche[(min(e[i][j], i), max(e[i][j], i))] != []:
      matche[(min(e[i][j], i), max(e[i][j], i))].append((min(i, e[i][j + 1]), max(i, e[i][j + 1])))
    else:
      matche[(min(e[i][j], i), max(e[i][j], i))].append((min(i, e[i][j + 1]), max(i, e[i][j + 1])))
    #print(i, j, matche)
#print(matche)
matchkey = dc(matche)
S = matchkey.keys()
visited = dd(int)
depth = 0
#print(S)
def dfs(s):
  if time.time() - st > 1.90:
    print(N * (N - 1) // 2)
  global visited
  global depth
  temp = 0
  #print(s)
  if matche[s] != []:
    for c in matche[s]:
      if visited[c] == 1:
        print(-1)
        #print(visited, c)
        exit(0)
      else:
        depth += 1
        visited[c] = 1
        #print(depth)
        temp = max(dfs(c), temp)
        depth -= 1
        visited[c] = 0
  else:
    return depth
  return temp
temp = 0
for s in S:
  temp = max(dfs(s), temp)
print(temp + 1)

Fixed submission:
N = int(input())
A = []
for i in range(N):
  A.append(list(map(int, input().split())))
#試合にコードを割り当てる
#of[l] = 前の番号の競技者の「既に数え上げた試合の数」
#r = 相手
#l = じぶん
def code(l, r, of):
  if l > r:
      l, r = r, l
  return of[l] + r - l - 1
#オフセットを作る。重複の試合を取り除くため、
#1ならN - 1試合、2ならN - 2試合...という風にする
of = [0] * (N + 1)
for i in range(N):
  of[i + 1] = of[i] + N - i - 1
#print(of)
#試合の前後関係を持つグラフ
#たぶんDAGになっている。なってないなら試合組めないと思う
g = [[] for _ in range(N * (N - 1) // 2)]
for i in range(N):
  for j in range(N - 2):
      fcode = code(i, A[i][j] - 1, of)
      tcode = code(i, A[i][j + 1] - 1, of)
      g[fcode].append(tcode)
#print(g)
def sort_topologically(g):
  n = len(g)
  #ecはコードによる試合頂点の入次数を記録
  ec = [0] * n
  for i in range(n):
    for e in g[i]:
      ec[e] += 1
  #print(ec)
  #retは入次数0の頂点を順にとってきている
  ret = [0] * n
  q = 0
  for i in range(n):
    if ec[i] == 0:
      ret[q] = i
      q += 1
  #p = 参照中の入次数0の試合
  #q = 入次数0の頂点数
  #while文はp == qの時点で終わる
  #for文では、入次数0の頂点pから出る有向辺を除去する
  #その上で入次数0の頂点が増えればretへ追加
  #このretは確かにトポロジカル順序になる
  p = 0
  #print(ret)
  while p < q:
    for to in g[ret[p]]:
      ec[to] -= 1
      if ec[to] == 0:
        ret[q] = to
        q += 1
    p += 1
  #ソートが終わったなら全ての辺は除去済みのはずである
  #このグラフは一応連結しているはずなので閉路検知ができる
  for i in range(n):
    if ec[i] > 0:
      return None
  return ret

od = sort_topologically(g)
#print(od)
#Noneなら閉路を持つので試合構築不可能
if not od:
  print(-1)
else:
  #dp = トポロジカル順序を持つ順序集合の先頭からi番目までを見た際の最大パス長
  dp = [1] * (N * (N - 1) // 2)
  for i in range(N * (N - 1) // 2):
    for e in g[od[i]]:
      dp[e] = max(dp[e], dp[od[i]] + 1)
  #print(dp)
  print(max(dp))

Buggy python submission (verdict: Time Limit Exceeded):
from collections import defaultdict as dd
from copy import deepcopy as dc
import time
st = time.time()
N = int(input())
e = dd(list)

matche = dd(list)

for i in range(1, N + 1):
  e[i] = list(map(int, input().split()))

for i in range(1, N + 1):
  for j in range(N - 2):
    if matche[(min(e[i][j], i), max(e[i][j], i))] != []:
      matche[(min(e[i][j], i), max(e[i][j], i))].append((min(i, e[i][j + 1]), max(i, e[i][j + 1])))
    else:
      matche[(min(e[i][j], i), max(e[i][j], i))].append((min(i, e[i][j + 1]), max(i, e[i][j + 1])))
    #print(i, j, matche)
#print(matche)
matchkey = dc(matche)
S = matchkey.keys()
visited = dd(int)
depth = 0
#print(S)
def dfs(s):
  if time.time() - st > 1.97:
    print(N * (N - 1) // 2)
  global visited
  global depth
  temp = 0
  #print(s)
  if matche[s] != []:
    for c in matche[s]:
      if visited[c] == 1:
        print(-1)
        #print(visited, c)
        exit(0)
      else:
        depth += 1
        visited[c] = 1
        #print(depth)
        temp = max(dfs(c), temp)
        depth -= 1
        visited[c] = 0
  else:
    return depth
  return temp
temp = 0
for s in S:
  temp = max(dfs(s), temp)
print(temp + 1)

Fixed submission:
N = int(input())
A = []
for i in range(N):
  A.append(list(map(int, input().split())))
#試合にコードを割り当てる
#of[l] = 前の番号の競技者の「既に数え上げた試合の数」
#r = 相手
#l = じぶん
def code(l, r, of):
  if l > r:
      l, r = r, l
  return of[l] + r - l - 1
#オフセットを作る。重複の試合を取り除くため、
#1ならN - 1試合、2ならN - 2試合...という風にする
of = [0] * (N + 1)
for i in range(N):
  of[i + 1] = of[i] + N - i - 1
#print(of)
#試合の前後関係を持つグラフ
#たぶんDAGになっている。なってないなら試合組めないと思う
g = [[] for _ in range(N * (N - 1) // 2)]
for i in range(N):
  for j in range(N - 2):
      fcode = code(i, A[i][j] - 1, of)
      tcode = code(i, A[i][j + 1] - 1, of)
      g[fcode].append(tcode)
#print(g)
def sort_topologically(g):
  n = len(g)
  #ecはコードによる試合頂点の入次数を記録
  ec = [0] * n
  for i in range(n):
    for e in g[i]:
      ec[e] += 1
  #print(ec)
  #retは入次数0の頂点を順にとってきている
  ret = [0] * n
  q = 0
  for i in range(n):
    if ec[i] == 0:
      ret[q] = i
      q += 1
  #p = 参照中の入次数0の試合
  #q = 入次数0の頂点数
  #while文はp == qの時点で終わる
  #for文では、入次数0の頂点pから出る有向辺を除去する
  #その上で入次数0の頂点が増えればretへ追加
  #このretは確かにトポロジカル順序になる
  p = 0
  #print(ret)
  while p < q:
    for to in g[ret[p]]:
      ec[to] -= 1
      if ec[to] == 0:
        ret[q] = to
        q += 1
    p += 1
  #ソートが終わったなら全ての辺は除去済みのはずである
  #このグラフは一応連結しているはずなので閉路検知ができる
  for i in range(n):
    if ec[i] > 0:
      return None
  return ret

od = sort_topologically(g)
#print(od)
#Noneなら閉路を持つので試合構築不可能
if not od:
  print(-1)
else:
  #dp = トポロジカル順序を持つ順序集合の先頭からi番目までを見た際の最大パス長
  dp = [1] * (N * (N - 1) // 2)
  for i in range(N * (N - 1) // 2):
    for e in g[od[i]]:
      dp[e] = max(dp[e], dp[od[i]] + 1)
  #print(dp)
  print(max(dp))

Buggy python submission (verdict: Time Limit Exceeded):
from collections import defaultdict as dd
from copy import deepcopy as dc
N = int(input())
e = dd(list)

matche = dd(list)

for i in range(1, N + 1):
  e[i] = list(map(int, input().split()))

for i in range(1, N + 1):
  for j in range(N - 2):
    if matche[(min(e[i][j], i), max(e[i][j], i))] != []:
      matche[(min(e[i][j], i), max(e[i][j], i))].append((min(i, e[i][j + 1]), max(i, e[i][j + 1])))
    else:
      matche[(min(e[i][j], i), max(e[i][j], i))].append((min(i, e[i][j + 1]), max(i, e[i][j + 1])))
    #print(i, j, matche)
#print(matche)
matchkey = dc(matche)
S = matchkey.keys()
visited = dd(int)
depth = 0
#print(S)
def dfs(s):
  global visited
  global depth
  temp = 0
  #print(s)
  if matche[s] != []:
    for c in matche[s]:
      if visited[c] == 1:
        print(-1)
        #print(visited, c)
        exit(0)
      else:
        depth += 1
        visited[c] = 1
        #print(depth)
        temp = max(dfs(c), temp)
        depth -= 1
        visited[c] = 0
  else:
    return depth
  return temp
temp = 0
for s in S:
  temp = max(dfs(s), temp)
print(temp + 1)

Fixed submission:
N = int(input())
A = []
for i in range(N):
  A.append(list(map(int, input().split())))
#試合にコードを割り当てる
#of[l] = 前の番号の競技者の「既に数え上げた試合の数」
#r = 相手
#l = じぶん
def code(l, r, of):
  if l > r:
      l, r = r, l
  return of[l] + r - l - 1
#オフセットを作る。重複の試合を取り除くため、
#1ならN - 1試合、2ならN - 2試合...という風にする
of = [0] * (N + 1)
for i in range(N):
  of[i + 1] = of[i] + N - i - 1
#print(of)
#試合の前後関係を持つグラフ
#たぶんDAGになっている。なってないなら試合組めないと思う
g = [[] for _ in range(N * (N - 1) // 2)]
for i in range(N):
  for j in range(N - 2):
      fcode = code(i, A[i][j] - 1, of)
      tcode = code(i, A[i][j + 1] - 1, of)
      g[fcode].append(tcode)
#print(g)
def sort_topologically(g):
  n = len(g)
  #ecはコードによる試合頂点の入次数を記録
  ec = [0] * n
  for i in range(n):
    for e in g[i]:
      ec[e] += 1
  #print(ec)
  #retは入次数0の頂点を順にとってきている
  ret = [0] * n
  q = 0
  for i in range(n):
    if ec[i] == 0:
      ret[q] = i
      q += 1
  #p = 参照中の入次数0の試合
  #q = 入次数0の頂点数
  #while文はp == qの時点で終わる
  #for文では、入次数0の頂点pから出る有向辺を除去する
  #その上で入次数0の頂点が増えればretへ追加
  #このretは確かにトポロジカル順序になる
  p = 0
  #print(ret)
  while p < q:
    for to in g[ret[p]]:
      ec[to] -= 1
      if ec[to] == 0:
        ret[q] = to
        q += 1
    p += 1
  #ソートが終わったなら全ての辺は除去済みのはずである
  #このグラフは一応連結しているはずなので閉路検知ができる
  for i in range(n):
    if ec[i] > 0:
      return None
  return ret

od = sort_topologically(g)
#print(od)
#Noneなら閉路を持つので試合構築不可能
if not od:
  print(-1)
else:
  #dp = トポロジカル順序を持つ順序集合の先頭からi番目までを見た際の最大パス長
  dp = [1] * (N * (N - 1) // 2)
  for i in range(N * (N - 1) // 2):
    for e in g[od[i]]:
      dp[e] = max(dp[e], dp[od[i]] + 1)
  #print(dp)
  print(max(dp))

Buggy python submission (verdict: Time Limit Exceeded):
from collections import defaultdict as dd
from copy import deepcopy as dc
N = int(input())
e = dd(list)

matche = dd(list)

for i in range(1, N + 1):
  e[i] = list(map(int, input().split()))

for i in range(1, N + 1):
  for j in range(N - 2):
    if matche[(min(e[i][j], i), max(e[i][j], i))] != []:
      matche[(min(e[i][j], i), max(e[i][j], i))].append((min(i, e[i][j + 1]), max(i, e[i][j + 1])))
    else:
      matche[(min(e[i][j], i), max(e[i][j], i))].append((min(i, e[i][j + 1]), max(i, e[i][j + 1])))
    #print(i, j, matche)
#print(matche)
matchkey = dc(matche)
S = matchkey.keys()
visited = dd(int)
depth = 0
#print(S)
def dfs(s):
  global visited
  global depth
  temp = 0
  #print(s)
  if matche[s] != []:
    for c in matche[s]:
      if visited[c] == 1:
        print(-1)
        #print(visited, c)
        exit(0)
      else:
        depth += 1
        visited[c] = 1
        #print(depth)
        temp = max(dfs(c), temp)
        depth -= 1
        visited[c] = 0
  else:
    return depth
  return temp
temp = 0
for s in S:
  temp = max(dfs(s), temp)
print(temp + 1)

Fixed submission:
N = int(input())
A = []
for i in range(N):
  A.append(list(map(int, input().split())))
#試合にコードを割り当てる
#of[l] = 前の番号の競技者の「既に数え上げた試合の数」
#r = 相手
#l = じぶん
def code(l, r, of):
  if l > r:
      l, r = r, l
  return of[l] + r - l - 1
#オフセットを作る。重複の試合を取り除くため、
#1ならN - 1試合、2ならN - 2試合...という風にする
of = [0] * (N + 1)
for i in range(N):
  of[i + 1] = of[i] + N - i - 1
#print(of)
#試合の前後関係を持つグラフ
#たぶんDAGになっている。なってないなら試合組めないと思う
g = [[] for _ in range(N * (N - 1) // 2)]
for i in range(N):
  for j in range(N - 2):
      fcode = code(i, A[i][j] - 1, of)
      tcode = code(i, A[i][j + 1] - 1, of)
      g[fcode].append(tcode)
#print(g)
def sort_topologically(g):
  n = len(g)
  #ecはコードによる試合頂点の入次数を記録
  ec = [0] * n
  for i in range(n):
    for e in g[i]:
      ec[e] += 1
  #print(ec)
  #retは入次数0の頂点を順にとってきている
  ret = [0] * n
  q = 0
  for i in range(n):
    if ec[i] == 0:
      ret[q] = i
      q += 1
  #p = 参照中の入次数0の試合
  #q = 入次数0の頂点数
  #while文はp == qの時点で終わる
  #for文では、入次数0の頂点pから出る有向辺を除去する
  #その上で入次数0の頂点が増えればretへ追加
  #このretは確かにトポロジカル順序になる
  p = 0
  #print(ret)
  while p < q:
    for to in g[ret[p]]:
      ec[to] -= 1
      if ec[to] == 0:
        ret[q] = to
        q += 1
    p += 1
  #ソートが終わったなら全ての辺は除去済みのはずである
  #このグラフは一応連結しているはずなので閉路検知ができる
  for i in range(n):
    if ec[i] > 0:
      return None
  return ret

od = sort_topologically(g)
#print(od)
#Noneなら閉路を持つので試合構築不可能
if not od:
  print(-1)
else:
  #dp = トポロジカル順序を持つ順序集合の先頭からi番目までを見た際の最大パス長
  dp = [1] * (N * (N - 1) // 2)
  for i in range(N * (N - 1) // 2):
    for e in g[od[i]]:
      dp[e] = max(dp[e], dp[od[i]] + 1)
  #print(dp)
  print(max(dp))