Problem:
7 パズル

7 パズルは 8 つの正方形のカードとこれらのカードがぴたりと収まる枠で構成されています。それぞれのカードには、互いに区別できるように 0, 1, 2, ..., 7 と番号がつけられています。枠には、縦に 2 個、横に 4 個のカードを並べることができます。

7 パズルを始めるときには、まず枠にすべてのカードを入れます。枠のなかで 0 のカードだけは、上下左右に隣接するカードと位置を交換することができます。たとえば、枠の状態が図(a) のときに、0 のカードの右に隣接した、7 のカードと位置を交換すれば、図(b) の状態になります。あるいは、図(a) の状態から 0 のカードの下に隣接した 2 のカードと位置を交換すれば図(c) の状態になります。図(a) の状態で 0 のカードと上下左右に隣接するカードは 7 と 2 のカードだけなので、これ以外の位置の入れ替えは許されません。

ゲームの目的は、カードをきれいに整列して図(d) の状態にすることです。最初の状態を入力とし、カードをきれいに整列するまでに、必要な最小手数を出力するプログラムを作成してください。ただし、入力されたカードの状態からは図(d) の状態に移ることは可能であるとします。

入力データは、1 行に 8 つの数字が空白区切りで与えられます。これらは、最初の状態のカードの並びを表します。例えば、図(a) の数字表現は0 7 3 4 2 5 1 6 に、図(c) は 2 7 3 4 0 5 1 6 となります。

図(a) 0 7 3 4 2 5 1 6 の場合

図(b) 7 0 3 4 2 5 1 6 の場合

図(c) 2 7 3 4 0 5 1 6 の場合

図(d) 0 1 2 3 4 5 6 7 (最終状態)

Input

上記形式で複数のパズルが与えられます。入力の最後まで処理してください。
与えられるパズルの数は 1,000 以下です。

Output

各パズルについて、最終状態へ移行する最小手数を１行に出力してください。

Sample Input

0 1 2 3 4 5 6 7
1 0 2 3 4 5 6 7
7 6 5 4 3 2 1 0

Output for the Sample Input

0
1
28

Solution in C# (judge verdict: Time Limit Exceeded)

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

class Program
{
    static readonly int H = 2, W = 4;
    int GoalMask;

    void Solve()
    {
        GoalMask = 0;
        for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) Set(i, j, i * W + j, ref GoalMask);
        string s;
        while (!string.IsNullOrEmpty(s = Console.ReadLine()))
        {
            Console.WriteLine(Go(s));
        }
    }

    int Go(string s)
    {
        int mask = 0;
        int si = 0, sj = 0;
        var A = Array.ConvertAll(s.Split(), int.Parse);
        for (int i = 0; i < H; i++)
            for (int j = 0; j < W; j++)
            {
                Set(i, j, A[i * W + j], ref mask);
                if (A[i * W + j] == 0) { si = i; sj = j; }
            }
        if (mask == GoalMask) return 0;
        bool[] seen = new bool[1 << (3 * 8)];
        var que = new Queue<int>();
        que.Enqueue(mask);
        que.Enqueue(si);
        que.Enqueue(sj);
        que.Enqueue(0);

        while (que.Count > 0)
        {
            mask = que.Dequeue();
            int i = que.Dequeue();
            int j = que.Dequeue();
            int cost = que.Dequeue();

            for (int d = 0; d < di.Length; d++)
            {
                int ni = i + di[d], nj = j + dj[d];
                if (IsInside(ni, nj))
                {
                    int next = mask;
                    Set(i, j, Get(ni, nj, next), ref next);
                    Set(ni, nj, 0, ref next);
                    if (!seen[next])
                    {
                        if (next == GoalMask) return cost + 1;
                        seen[next] = true;
                        que.Enqueue(next);
                        que.Enqueue(ni);
                        que.Enqueue(nj);
                        que.Enqueue(cost + 1);
                    }
                }
            }
        }
        return int.MaxValue;
    }

    int Get(int i, int j, int mask)
    {
        return (mask >> (3 * (i * W + j))) & 7;
    }
    void Set(int i, int j, int num, ref int mask)
    {
        mask &= ~(7 << (3 * (i * W + j)));
        mask |= num << (3 * (i * W + j));
    }

    static readonly int[] di = { 0, 0, -1, 1 };
    static readonly int[] dj = { -1, 1, 0, 0 };
    bool IsInside(int i, int j)
    {
        return i >= 0 && i < H && j >= 0 && j < W;
    }

    static void Main()
    {
        new Program().Solve(); 
    }

    //static Read read = new Read();
    class Read
    {
        private Queue<string> que = new Queue<string>();
        public string String() { return Dequeue(); }
        public int Int() { return int.Parse(Dequeue()); }
        public long Long() { return long.Parse(Dequeue()); }
        public double Double() { return double.Parse(Dequeue()); }
        public int[] IntArray() { return Array.ConvertAll(Console.ReadLine().Split(), int.Parse); }
        public string[] StringArray(int N) { return Enumerable.Range(0, N).Select(i => Console.ReadLine()).ToArray(); }
        private string Dequeue()
        {
            if (que.Count == 0) foreach (var s in Console.ReadLine().Split()) que.Enqueue(s);
            return que.Dequeue();
        }
    }
}