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 C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;

namespace Competitive
{
    internal class Solution
    {
        public int N, M;
        public int[] InitPos, Goal1, Goal2;
        public long HashGoal1, HashGoal2;
        public int[] InitMx;
        public HashSet<long> Used;
        public int ret;
        public void Run()
        {
            while (true)
            {
                {
                    var line = Input.ReadIntArray();
                    N = line[0];
                    M = line[1];
                }

                if (N == 0 && M == 0) return;
                InitPos = new int[N];

                for (int i = 0; i < 3; i++)
                {
                    var line = Input.ReadIntArray().Skip(1).Select(e => e - 1);
                    foreach (var e in line)
                    {
                        InitPos[e] = i;
                    }
                }

                InitMx = MX(InitPos);

                Goal1 = new int[N];
                Goal2 = new int[N];
                for (int i = 0; i < N; i++)
                {
                    Goal1[i] = 0;
                    Goal2[i] = 2;
                }

                HashGoal1 = Hash(Goal1);
                HashGoal2 = Hash(Goal2);

                ret = -1;
                BFS(InitPos, InitMx);

                Console.WriteLine(ret);
            }
         
        }

        public void BFS(int[] pos, int[] mx)
        {
            Used = new HashSet<long>();

            var queue = new Queue<Data>();
            queue.Enqueue(new Data { dist = 0, pos = pos, mx=mx });
            while (queue.Count > 0)
            {
                var d = queue.Dequeue();
                var hash = Hash(d.pos);

                // Check
                if (d.dist > M) continue;
                if (Used.Contains(hash)) continue;
                Used.Add(hash);
               

                // Check Goal
                if (hash == HashGoal1 || hash == HashGoal2)
                {
                    ret = d.dist;
                    break;
                }

                // Move
                // Console.Error.WriteLine(string.Join(", ", d.pos) + " - " + string.Join(", ", d.mx));
                
                if (d.mx[0] < d.mx[1])
                {
                    var p = d.pos.ToArray();
                    p[d.mx[1]] = 0;
                    queue.Enqueue(new Data {dist = d.dist + 1, pos = p, mx = MX(p)});
                }
                else
                {
                    var p = d.pos.ToArray();
                    p[d.mx[0]] = 1;
                    queue.Enqueue(new Data { dist = d.dist + 1, pos = p, mx = MX(p) });
                }

                if (d.mx[1] < d.mx[2])
                {
                    var p = d.pos.ToArray();
                    p[d.mx[2]] = 1;
                    queue.Enqueue(new Data { dist = d.dist + 1, pos = p, mx = MX(p) });
                }
                else
                {
                    var p = d.pos.ToArray();
                    p[d.mx[1]] = 2;
                    queue.Enqueue(new Data { dist = d.dist + 1, pos = p, mx = MX(p) });
                }
            }
        }

        public long Hash(int[] pos)
        {
            long m = 1;
            long ret = 0;
            for (int i = 0; i < pos.Length; i++)
            {
                ret += m * pos[i];
                m *= 3;
            }
            return ret;
        }

        public int[] MX(int[] pos)
        {
            int[] ret = new int[3];
            for (int i = 0; i < 3; i++)
            {
                ret[i] = -1;
            }
            for (int i = 0; i < pos.Length; i++)
            {
                ret[pos[i]] = i;
            }
            return ret;
        }
    }

    // libs ----------
    class Data
    {
        public int dist;
        public int[] pos;
        public int[] mx;
    }

    // common ----------

    internal static class Input
    {
        public static string ReadString()
        {
            string line = Console.ReadLine();
            return line;
        }

        public static int ReadInt()
        {
            string line = Console.ReadLine();
            return int.Parse(line);
        }

        public static int[] ReadIntArray()
        {
            string line = Console.ReadLine();
            return line.Split(' ').Select(int.Parse).ToArray();            
        }

        public static long ReadLong()
        {
            string line = Console.ReadLine();
            return long.Parse(line);
        }

        public static long[] ReadLongArray()
        {
            string line = Console.ReadLine();
            return line.Split(' ').Select(long.Parse).ToArray();
        }

        public static double[] ReadDoubleArray()
        {
            string line = Console.ReadLine();
            return line.Split(' ').Select(double.Parse).ToArray();
        }
    }
    
    internal class Program
    {
        public static void Main(string[] args)
        {
            var s = new Solution();
            s.Run();
        }
    }
}