Problem:
Score : 500 points

Problem Statement

N players will participate in a tennis tournament. We will call them Player 1, Player 2, \ldots, Player N.

The tournament is round-robin format, and there will be N(N-1)/2 matches in total.
Is it possible to schedule these matches so that all of the following conditions are satisfied? If the answer is yes, also find the minimum number of days required.

Each player plays at most one matches in a day.

Each player i (1 \leq i \leq N) plays one match against Player A_{i, 1}, A_{i, 2}, \ldots, A_{i, N-1} in this order.

Constraints

3 \leq N \leq 1000

1 \leq A_{i, j} \leq N

A_{i, j} \neq i

A_{i, 1}, A_{i, 2}, \ldots, A_{i, N-1} are all different.

Input

Input is given from Standard Input in the following format:

N
A_{1, 1} A_{1, 2} \ldots A_{1, N-1}
A_{2, 1} A_{2, 2} \ldots A_{2, N-1}
:
A_{N, 1} A_{N, 2} \ldots A_{N, N-1}

Output

If it is possible to schedule all the matches so that all of the conditions are satisfied, print the minimum number of days required; if it is impossible, print -1.

Sample Input 1

3
2 3
1 3
1 2

Sample Output 1

3

All the conditions can be satisfied if the matches are scheduled for three days as follows:

Day 1: Player 1 vs Player 2

Day 2: Player 1 vs Player 3

Day 3: Player 2 vs Player 3

This is the minimum number of days required.

Sample Input 2

4
2 3 4
1 3 4
4 1 2
3 1 2

Sample Output 2

4

All the conditions can be satisfied if the matches are scheduled for four days as follows:

Day 1: Player 1 vs Player 2, Player 3 vs Player 4

Day 2: Player 1 vs Player 3

Day 3: Player 1 vs Player 4, Player 2 vs Player 3

Day 4: Player 2 vs Player 4

This is the minimum number of days required.

Sample Input 3

3
2 3
3 1
1 2

Sample Output 3

-1

Any scheduling of the matches violates some condition.

Solution in Rust (1.15.1) (judge verdict: Accepted)

//! ----------------------------------------------
//! Framework <https://github.com/vain0x/procon>
//!
//! See the bottom of file for solution.
//! ----------------------------------------------

#![allow(unused_imports)]
#![allow(non_snake_case)]

use std::cell::RefCell;
use std::cmp::{max, min, Ordering};
use std::collections::*;
use std::fmt::{Debug, Display, Formatter, Write as FmtWrite};
use std::io::{stderr, stdin, BufRead, Write};
use std::mem::{replace, swap};
use std::ops::*;
use std::rc::Rc;

/// Print values to standard error if debug mode.
#[allow(unused_macros)]
macro_rules! debug {
    ($($e:expr),*) => {
        #[cfg(debug_assertions)]
        $({
            let (e, mut err) = (stringify!($e), stderr());
            writeln!(err, "\x1B[33m{}\x1B[0m = {:?}", e, $e).unwrap()
        })*
    };
}

/// Read from standard input and parse each word.
/// - `read!(T, U, ..)` parses a line as a tuple of words.
/// - `read![[T]]` parses a line as an array of words.
/// - `read![..; N]` parses `N` lines, using `read!(..)` repeatedly.
#[allow(unused_macros)]
macro_rules! read {
    ([$t:ty] ; $n:expr) =>
        ((0..$n).map(|_| read!([$t])).collect::<Vec<_>>());
    ($($t:ty),+ ; $n:expr) =>
        ((0..$n).map(|_| read!($($t),+)).collect::<Vec<_>>());
    ([$t:ty]) =>
        (rl().split_whitespace().map(|w| w.parse().unwrap()).collect::<Vec<$t>>());
    ($($t:ty),*) => {{
        let buf = rl();
        let mut w = buf.split_whitespace();
        ($(w.next().unwrap().parse::<$t>().unwrap()),*)
    }};
}

/// Read a line from standard input.
#[allow(dead_code)]
fn rl() -> String {
    let mut buf = String::new();
    stdin().read_line(&mut buf).unwrap();

    #[allow(deprecated)]
    buf.trim_right().to_owned()
}

// -----------------------------------------------
// Solution
// -----------------------------------------------

use Color::*;

/// 閉路検出中の頂点の色
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Color {
    /// 処理前の頂点の色
    White,

    /// 処理が実行中 (再帰処理の途中) の頂点の色
    Gray,

    /// 処理済みの頂点の色
    Black,
}

struct Solver {
    /// 選手数
    N: usize,

    /// A[u][i] = v : 選手 u が i 番目に選手 v と戦う。
    A: Vec<Vec<usize>>,

    /// order[u][v] = i : 選手 u が i 番目に選手 v と戦う。
    order: Vec<Vec<usize>>,

    /// opponents[u] : 選手 u の対戦相手が順番に出てくるキュー。
    opponents: Vec<VecDeque<usize>>,

    /// dirties : 前日の試合に参加した選手の集合。
    /// この集合に含まれる選手に限り、本日の試合に参加できる可能性がある。
    dirties: BTreeSet<usize>,
}

impl Solver {
    fn new(N: usize, A: Vec<Vec<usize>>) -> Solver {
        Solver {
            N: N,
            A: A,
            order: vec![vec![N; N]; N],
            opponents: vec![VecDeque::new(); N],
            dirties: BTreeSet::new(),
        }
    }

    /// 選手 u が選手 v と戦う試合の1つ前の試合で戦う相手
    fn prev_opponent(&self, u: usize, v: usize) -> Option<usize> {
        let ui = self.order[u][v];
        if ui == 0 {
            // u は v と最初に戦う
            return None;
        }

        Some(self.A[u][ui - 1])
    }

    /// u の次の対戦相手。試合できる状態でなければ None。
    fn ready_opponent(&self, u: usize) -> Option<usize> {
        let v = match self.opponents[u].get(0) {
            None => return None,
            Some(&v) => v,
        };

        match self.opponents[v].get(0) {
            None => unreachable!(),
            Some(&w) if w != u => {
                // v は u 以外の選手と先に戦うので、今日は u と試合できない。
                return None;
            }
            Some(_) => return Some(v),
        }
    }

    /// 試合日程を矛盾なく構築できるか？
    /// 試合の前後関係の循環 (閉路) がなければ OK。
    fn is_consistent(&self) -> bool {
        /// u, v の試合を探索する。閉路を見つけたら true を返す。
        fn dfs(mut u: usize, mut v: usize, solver: &Solver, colors: &mut Vec<Vec<Color>>) -> bool {
            if u > v {
                swap(&mut u, &mut v);
            }
            assert!(u < v);

            match colors[u][v] {
                Black => return false,
                Gray => {
                    // この試合の再帰処理中に再訪問しているので、閉路があったことになる。
                    return true;
                }
                White => {}
            }

            colors[u][v] = Gray;

            // u, v　が互いに相手と戦う直前の試合で戦う相手との試合を探索する。
            if let Some(w) = solver.prev_opponent(u, v) {
                if dfs(u, w, solver, colors) {
                    return true;
                }
            }

            if let Some(w) = solver.prev_opponent(v, u) {
                if dfs(v, w, solver, colors) {
                    return true;
                }
            }

            colors[u][v] = Black;

            false
        }

        let mut colors = vec![vec![White; self.N]; self.N];
        for u in 0..self.N {
            for v in u + 1..self.N {
                if dfs(u, v, self, &mut colors) {
                    // 閉路があったら矛盾
                    return false;
                }

                assert_eq!(colors[u][v], Black);
            }
        }

        // 無矛盾
        true
    }

    /// 最小の日数を求める。
    fn solve(mut self) -> Option<usize> {
        let N = self.N;

        // 準備
        for u in 0..N {
            for ui in 0..self.A[u].len() {
                let v = self.A[u][ui];
                self.order[u][v] = ui;
                self.opponents[u].push_back(v);
            }

            self.dirties.insert(u);
        }

        // 矛盾の検出
        if !self.is_consistent() {
            return None;
        }

        // 日程の構築
        let mut day_count = 0;
        let mut next_dirties = BTreeSet::new();

        loop {
            debug!(day_count);

            next_dirties.clear();

            for &u in self.dirties.iter() {
                let v = match self.ready_opponent(u) {
                    None => continue,
                    Some(v) => v,
                };

                debug!((u, v));

                next_dirties.insert(u);
                next_dirties.insert(v);
            }

            for &u in next_dirties.iter() {
                self.opponents[u].pop_front();
            }

            // 試合が行われなかったので終了。
            if next_dirties.is_empty() {
                break;
            }

            swap(&mut self.dirties, &mut next_dirties);
            day_count += 1;
        }

        assert!((0..N).all(|u| self.opponents[u].is_empty()));

        Some(day_count)
    }
}

fn main() {
    let N = read!(usize);
    let mut A = read![[usize]; N];

    // 選手の番号を 0-indexed に変換。
    for i in 0..N {
        for x in A[i].iter_mut() {
            *x -= 1;
        }
    }

    match Solver::new(N, A).solve() {
        None => println!("-1"),
        Some(day_count) => println!("{}", day_count),
    }
}