
import qualified Data.Vector.Unboxed as U
import qualified Data.Vector as V
import qualified Data.ByteString.Char8 as C
--import qualified Data.Array.IO as A
import Debug.Trace
import Data.List
import Control.Monad
--import Data.Ord
--import qualified Data.IntSet as S
import qualified Data.Map as M

r :: Int -> IO (V.Vector Int)
r n = V.unfoldrN n (C.readInt . C.dropWhile (==' ')) <$> C.getLine

r' :: IO [Int]
r'  =   unfoldr    (C.readInt . C.dropWhile (==' ')) <$> C.getLine

{-
rp :: IO (Int,Int)
rp  = toTup . unfoldr    (C.readInt . C.dropWhile (==' ')) <$> C.getLine
-}

toTup [a,b] = (a,b)
toLst (a,b) = [a,b]
swTup (a,b) = (b,a)
ordTup (a,b)
    | a<b = (a,b)
    | True = (b,a)


main :: IO ()
main = do
    n <- readLn :: IO Int
    as <- join <$> V.generateM n (\i -> do
            ais <- r (n-1)
            let ix = i+1
            return $ V.zip (V.map (makeOrdTup ix) ais) (V.generate (n-1) ((:[]).succ))
        )
    let mp = M.map (ordTup.toTup) $ M.fromListWith (++) (V.toList as) :: M.Map (Int,Int) (Int,Int)
    let mp' = map ( (\(a,b)-> (a,[b])) . swTup) (M.toList mp) :: [ ((Int,Int),[(Int,Int)]) ]
    let mp'' = M.fromListWith (++) mp' :: M.Map (Int,Int) [(Int,Int)]
    let mp''' = M.map (sort . concat . map toLst) mp''
    print $ if check mp''' then length mp''' else -1

check :: M.Map (Int,Int) [Int] -> Bool
check = and . M.elems . (M.map (\ls -> (nub ls) == ls))


makeOrdTup :: Int -> Int -> (Int,Int)
makeOrdTup a b
    | a < b     = (a,b)
    | otherwise = (b,a)


dup :: Int -> [Int] -> Bool
dup ac [] = True
dup ac (h:t) = ac==h || dup h t