import std.algorithm;
import std.bigint;
import std.concurrency;
import std.container;
import std.conv;
import std.functional;
import std.math;
import std.meta;
import std.random;
import std.range;
import std.stdio;
import std.string;
import std.traits;
import std.typecons;


auto solve(int N, int[][] A) {
    int[][] standby = new int[][](N, N);
    Tuple!(int, int)[] match;

    foreach (i; 0 .. N) {
        auto a = A[i];
        auto x = min(a.front - 1, i);
        auto y = max(a.front - 1, i);
        a.popFront;
        A[i] = a;
        if (++standby[x][y] == 2)
            match ~= tuple(x, y);
    }

    int ans;
    int done;
    Tuple!(int, int)[] nmatch = [];

    while (true) {
        ans++;
        foreach (t; match) {
            done++;
            auto x = t[0];
            auto y = t[1];

            if (!A[x].empty) {
                auto nx = A[x].front - 1;
                auto a = A[x];
                a.popFront;
                A[x] = a;
                auto x1 = min(x, nx);
                auto x2 = max(x, nx);
                if (++standby[x1][x2] == 2)
                    nmatch ~= tuple(x1, x2);
            }

            if (!A[y].empty) {
                auto ny = A[y].front - 1;
                auto a = A[y];
                a.popFront;
                A[y] = a;
                auto y1 = min(y, ny);
                auto y2 = max(y, ny);
                if (++standby[y1][y2] == 2)
                    nmatch ~= tuple(y1, y2);
            }  
        }
        if (nmatch.empty)
            break;
        match = nmatch[];
        nmatch = [];
    }

    if (done == N * (N - 1) / 2)
        return ans;
    return -1;
}


void main() {
    auto input = stdin.byLine.map!split.joiner;

    int N;
    N = input.front.to!int;
    input.popFront;

    int[][] A = new int[][](cast(size_t) (N), cast(size_t) (N-1));
    foreach (i; 0 .. cast(size_t) (N)) {
        foreach (j; 0 .. cast(size_t) (N-1)) {
            A[i][j] = input.front.to!int;
            input.popFront;
        }
    }

    static if (is(ReturnType!solve == void))
        solve(N, A);
    else
        solve(N, A).writeln;
}
