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 JAVA (judge verdict: Memory Limit Exceeded)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class Main {

	public static void main(String[] args) throws IOException {
		// TODO ?????????????????????????????????????????????
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		while(true){
			String[] tmpArray = br.readLine().split(" ");
			int n = Integer.parseInt(tmpArray[0]);
			int m = Integer.parseInt(tmpArray[1]);

			if(n == 0 && m == 0) break;

			TrayController tc = new TrayController();

			//System.out.println(n + " "+ m);
			//?????¬???????????????
			for(int i = 0; i < 3 ; i++){
				tc.setTray(new Tray(br.readLine()), i);
				//System.out.println("tray" +i+" done");
			}

			//System.out.println("initialize completed");

			System.out.println(tc.calcTimes(m));
		}
	}

}

class TrayController {
	private Tray[] trays = new Tray[3];
	private int times = -1;

	public void setTray(Tray t, int index){
		trays[index] = t;
	}

	public int calcTimes (int m){

		moveCup (this.trays, m, -1, -1);

		if(times != -1) return m - times;
		else return -1;
	}

	private void moveCup (Tray[] trays, int m, int mode, int prevmode){
		//System.out.println("m = "+m+ "mode = "+mode);


		//A to B
		if(mode == 0){
			trays[1].push(trays[0].pop());
		}
		//B to C
		if(mode == 1){
			trays[2].push(trays[1].pop());
		}
		//C to B
		if(mode == 2){
			trays[1].push(trays[2].pop());
		}
		//B to A
		if(mode == 3){
			trays[0].push(trays[1].pop());
		}

		if(emptyCheck(trays)){
			//System.out.println("empty");
			if(times < m) {
				times = m;
			}
			return;
		}
		
		if(m == 0){
			/*
			System.out.println("time limeit");
			//?????¶??????top?????¨???
			for (int i = 0; i < 3; i++){
				System.out.print(trays[i].top());
			}
			System.out.println();
			*/
			return;
		}
		/*
		//?????¶??????top?????¨???
		for (int i = 0; i < 3; i++){
			System.out.print(trays[i].top());
		}
		System.out.println();
		*/

		Tray[] trayCopy = new Tray[3];
		//A to B
		if(prevmode != 3 && trays[0].top() > trays[1].top()) {
			copyTray(trayCopy, trays);
			moveCup(trayCopy, m - 1, 0, prevmode);
		}
		if(prevmode != 2 && trays[1].top() > trays[2].top()) {
			copyTray(trayCopy, trays);
			moveCup(trayCopy, m - 1, 1, prevmode);
		}
		if(prevmode != 1 && trays[2].top() > trays[1].top()) {
			copyTray(trayCopy, trays);
			moveCup(trayCopy.clone(), m - 1, 2, prevmode);
		}
		if(prevmode != 0 && trays[1].top() > trays[0].top()) {
			copyTray(trayCopy, trays);
			moveCup(trayCopy.clone(), m - 1, 3, prevmode);
		}
	}

	private void copyTray(Tray[] newTray, Tray[] origin){
		for (int i = 0 ; i < origin.length; i++){
			newTray[i] = new Tray(new ArrayList<Integer>(origin[i].getCups()));
		}
	}

	private boolean emptyCheck (Tray[] trays){
		if(trays[0].isEmpty() && trays[1].isEmpty()) {
			return true;
		}
		else if (trays[1].isEmpty() && trays[2].isEmpty()) {
			return true;
		}
		else {
			return false;
		}
	}
}

class Tray {
	private ArrayList<Integer> cups = new ArrayList<Integer>();


	public Tray(String str){
		String[] tmpArray = str.split(" ");

		for(int i = 1; i < tmpArray.length; i++){
			cups.add(Integer.parseInt(tmpArray[i]));
		}

		//System.out.println("cups "+ cups.size());

	}

	public Tray(ArrayList<Integer> cups){
		this.cups = cups;
	}

	public boolean isEmpty (){
		return cups.isEmpty();
	}

	public int top() {
		if (cups.size() == 0){
			return 0;
		}
		return cups.get(cups.size() - 1);
	}

	public int pop() {
		int tmp = top();
		cups.remove(cups.size() - 1);

		return tmp;
	}

	public void push(int n) {
		cups.add(n);
	}

	public ArrayList<Integer> getCups(){
		return cups;
	}
}