Problem:
MathJax.Hub.Config({
tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}
});

Airport Codes

空港コード

JAG王国では国内の空港にそれぞれ空港コードを割り当てて識別をしている．

空港コードは，小文字の英語アルファベットで表記した空港の名前をもとに以下の規則で割り当てられる:

名前の最初の文字と，母音 (a,i,u,e,o) の直後の文字を順に取り出す．

取り出した文字列が k 文字未満ならそれを空港コードとし， k 文字以上なら，その取り出した文字列の先頭 k 文字を空港コードとして使う．

例えば k = 3 のとき，haneda には hnd ， oookayama には ooo ， tsu には t というコードが割り当てられる．

しかしこのコードの割り当て方では，違う名前の空港でも同じコードが割り当てられることがあり，混乱を招いてしまう．
空港の名前の一覧が与えられるので，すべての空港のコードが異なるようにできるか判定して，可能な場合はすべての空港コードが異なるようにできる最小の k を求め，不可能な場合はその旨を伝えるプログラムを作成せよ．

Input

入力は100個以下のデータセットからなる．
それぞれのデータセットは次の形式で与えられる．

n
s1
...
sn

1行目に空港の数 n (2 ≤ n ≤ 50) が整数で与えられ，続く n 行にはそれぞれ空港の名前 si が文字列で与えられる．
空港の名前は'a'から'z'の小文字の英語アルファベットのみで構成され，いずれも文字数は1以上50以下である．
また，与えられる空港の名前はすべて異なる．すなわち，1 ≤ i < j ≤ n のとき si ≠ sj を満たす．

入力の終わりは1つのゼロだけからなる行で示される．

Output

それぞれのデータセットについて，すべての空港に相異なる空港コードを割り当てられるときは，そのような最小の k を1行に出力せよ．
不可能な場合は，-1を1行に出力せよ．

Sample Input

3
haneda
oookayama
tsu
2
azusa
azishirabe
2
snuke
snake
4
haneda
honda
hanamaki
hawaii
0

Output for Sample Input

1
4
-1
3

Solution in Rust (judge verdict: Accepted)

use std::io::{stdin, Read, StdinLock};
use std::str::FromStr;
use std::cmp;
use std::collections::BTreeSet;

struct Scanner<'a> {
    cin : StdinLock<'a>,
}

impl<'a> Scanner<'a> {
    fn new(cin : StdinLock<'a>) -> Scanner<'a> {
        Scanner { cin: cin }
    }

    fn read1<T: FromStr>(&mut self) -> Option<T> {
        let token = self.cin.by_ref().bytes().map(|c| c.unwrap() as char)
            .skip_while(|c| c.is_whitespace())
            .take_while(|c| !c.is_whitespace())
            .collect::<String>();
        token.parse::<T>().ok()
    }

    fn read<T: FromStr>(&mut self) -> T {
        self.read1().unwrap()
    }
}


fn into_code(name: &String, k: usize) -> Vec<char> {
    let boin : BTreeSet<char> = "aeiou".chars().collect();
    let mut cs = (*name).chars().collect::<Vec<char>>();
    let mut ret = Vec::<char>::new();
    ret.push(*(cs.first().unwrap()));
    for wd in cs.as_slice().windows(2) {
        let (prev, now) = (wd[0], wd[1]);
        if ret.len() == k {break;}
        if boin.contains(&prev) {
            ret.push(now);
        }
    }
    ret
}


fn main(){
	let cin = stdin();
	let cin = cin.lock();
	let mut sc = Scanner::new(cin);
    loop{
        let n : usize = sc.read();
        if n == 0 { break; }
        let mut names = Vec::new();
        let mut msize = 0;
        for _ in 0..n {
            names.push(sc.read::<String>());
            if msize < names.last().unwrap().len(){
                msize = names.last().unwrap().len();
            }
            //println!("{}", names.last().unwrap());
        }
        //println!("s:{}", msize);
        let mut ended = false;
        for k in 1..msize {
            let mut nms = BTreeSet::new();
            for name in &names {
                if !nms.insert(into_code(name, k)) {
                    break;
                }
            }
            if nms.len() == n {
                //for i in nms {
                    //println!("{:?}", i);
                //}
                println!("{}", k);
                ended = true;
                break;
            }
        }
        if !ended {
            let mut nms = BTreeSet::new();
            for name in &names {
                if !nms.insert(into_code(name, msize)) {
                    break;
                }
            }
            if nms.len() == n {
                //for i in nms {
                    //println!("{:?}", i);
                //}
                println!("{}", msize);
            } else {
                println!("-1");
            }
        }
    }
}