Problem:
大きさが異なる n 個のコップと 3 つのトレイ（お盆）A，B，C があり，それらのコップは 3 つのトレイの上にそれぞれ何個かずつ一山に重ねて置かれている．ただし，どのトレイにおいても，そのトレイの中で一番小さいコップが一番下に， 2 番目に小さいコップがその上に， 3 番目に小さいコップがその上にと，小さい順に伏せて重ねてある．例えば，下図の右側は， n = 5 個のコップがトレイ A，B，C にそれぞれ 2 個，0 個，3 個重ねて置かれている状態を示している．

このように，コップの初期状態が与えられたとき，次の規則 1 〜 3 を守りながら，すべてのコップを A または C のどちらかのトレイに移動させるには何回移動を行えばよいかを求めたい．

（規則 1） 1 回に 1 つのコップだけを移動させることができる．それは，そのトレイにあるコップの中で一番上のコップ（つまり，一番大きいコップ）である．

（規則 2）大きいコップの上に小さいコップを重ねてはいけない．

（規則 3）コップ 1 個の直接移動は，トレイ A から B，B から A，B から C，C から B のみが許され， A から C への直接移動や C から A への直接移動は許されない．

　n 個のコップの初期状態と整数 m が与えられたとき， m 回以内の移動で， A または C のどちらかのトレイにすべてのコップをまとめて重ねることができるかどうかを判定し，可能な場合には移動回数の最小値を，不可能な場合には -1 を出力するプログラムを作成しなさい．

　入力ファイルの 1 行目には， n と m がこの順に空白を区切り文字として書いてある． 1 ≦ n ≦ 15 であり， 1 ≦ m ≦ 15000000 である． 2 行目，3 行目，4 行目には， 1 から n までの整数を何個かずつ 3 つのグループに分けて，それぞれのグループ内で小さい順（昇順）に並べたものが書いてある．ただし，各行の先頭（それらの整数の前）には，それらの個数が書いてある． 2 行目に書かれている整数（先頭の 1 つを除く）はトレイ A の上に重ねられている各コップの大きさを表す．同様に， 3 行目に書かれている整数（先頭の 1 つを除く）はトレイ B の上に重ねられている各コップの大きさを表し， 4 行目に書かれている整数（先頭の１つを除く）はトレイ C の上に重ねられている各コップの大きさを表す．

入力例１

入力例２

入力例３

入力例４

3 10

4 20

2 5

3 3

0

2 1 2

2 1 2

0

1 1

1 3

0

1 1

2 2 3

1 4

0

2 2 3

　

出力例１

出力例２

出力例３

出力例４

9

3

0

-1

入力

入力は複数のデータセットからなる．n, m がともに 0 のとき入力が終了する．データセットの数は 5 を超えない．

出力

データセットごとに、移動回数または -1 を１行に出力する．

入力例

3 10
0
1 1
2 2 3
4 20
2 1 2
1 3
1 4
2 5
2 1 2
0
0
3 3
0
1 1
2 2 3
0 0

出力例

9
3
0
-1

各データセットの出力（移動回数または -1）の後に改行を入れること．

上記問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

Solution in OCaml (judge verdict: Memory Limit Exceeded)

type trays = Tray of int list * int list * int list

type move_command = AB | BA | BC | CB

let finished = function
  | Tray (_, [], []) | Tray ([], [], _) -> true
  | _ -> false

let move (Tray (as_, bs, cs)) command =
  let move xs ys = match xs, ys with
    | x :: xs, [] -> (xs, [x])
    | x :: xs, y :: ys when x > y -> (xs, x :: y :: ys)
    | _ -> invalid_arg "move" in
  try
    Some
      begin
        match command with
        | AB -> let as_, bs = move as_ bs in Tray (as_, bs, cs)
        | BA -> let bs, as_ = move bs as_ in Tray (as_, bs, cs)
        | BC -> let bs, cs = move bs cs in Tray (as_, bs, cs)
        | CB -> let cs, bs = move cs bs in Tray (as_, bs, cs)
      end
  with Invalid_argument _ -> None

let next_states state =
  List.fold_left
    (fun acc ->
     function
     | None -> acc
     | Some s -> s :: acc)
    []
  @@ List.map (move state) [CB; BC; BA; AB]

let search initial_state max_swaps =
  let states = Queue.create () in
  Queue.push (initial_state, 0) states;
  let seen = Hashtbl.create 1024 in
  let rec search () =
    if Queue.length states = 0 then -1
    else
      let state, count = Queue.pop states in
      if finished state then count
      else if count > max_swaps then -1
      else if Hashtbl.mem seen state then search ()
      else
        begin
          Hashtbl.add seen state true;
          List.iter
            (fun next_state -> Queue.push (next_state, succ count) states)
            @@ List.filter
                 (fun state -> not @@ Hashtbl.mem seen state)
                 (next_states state);
          search ()
        end in
  search ()

let read_lines n =
  let rec read_lines n acc =
    if n = 0 then List.rev acc
    else read_lines (pred n) ((read_line ()) :: acc) in
  read_lines n []

let split str delim =
  let len = String.length str in
  let rec split offset acc =
    try
      let index = String.index_from str offset delim in
      split (index + 1) ((String.sub str offset (index - offset)) :: acc)
    with Not_found -> List.rev ((String.sub str offset (len - offset)) :: acc) in
  split 0 []

let rec solve () =
  let read_tray () =
    List.rev @@ List.tl @@ List.map int_of_string @@ split (read_line ()) ' ' in
  let line = read_line () in
  let n_cups, max_swaps = Scanf.sscanf line "%d %d" (fun n m -> (n, m)) in
  if (n_cups, max_swaps) = (0, 0) then ()
  else
    let tray_a = read_tray () in
    let tray_b = read_tray () in
    let tray_c = read_tray () in
    print_endline @@ string_of_int
    @@ search (Tray (tray_a, tray_b, tray_c)) max_swaps;
    solve ()

let () = solve ()