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: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    struct Puzzle
    {
        internal int[] f;
        internal int space, MD;

        public Puzzle(int n)
        {
            f = new int[n];
            space = MD = default(int);
        }

        public Puzzle(Puzzle source)
        {
            f = (int[])source.f.Clone();

            space = source.space;
            MD = source.MD;
        }
    }

    class NPuzzle
    {
        readonly int Limit = 50;
        readonly int n, h, w;

        readonly int[] moveX = new int[] { 0, -1, 0, +1 };
        readonly int[] moveY = new int[] { -1, 0, +1, 0 };
        readonly char[] dir = new char[] { 'u', 'l', 'd', 'r' };

        int limit;
        int[] path;
        int[,] MDT;

        public NPuzzle(int h, int w)
        {
            this.h = h;
            this.w = w;
            n = h * w;

            MDT = new int[n, n];
            path = new int[Limit];

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    MDT[i, j] = Math.Abs(i / w - j / w) + Math.Abs(i % w - j % w);
                }
            }
        }

        public string IterativeDeeping(Puzzle p)
        {
            StringBuilder ret = new StringBuilder();
            Puzzle state;

            p.MD = GetAllMD(p);

            for (limit = p.MD; limit <= Limit; limit++)
            {
                state = new Puzzle(p);

                if (DFS(state, 0, -50))
                {
                    for (int i = 0; i < limit; i++)
                    {
                        ret.Append(dir[path[i]]);
                    }
                    return ret.ToString();
                }
            }
            return null;
        }

        private bool DFS(Puzzle state, int depth, int prev)
        {
            if (state.MD == 0) return true;

            if (depth + state.MD > limit) return false;

            int sx = state.space % w;
            int sy = state.space / w;

            Puzzle tempState;

            for (int r = 0; r < 4; r++)
            {
                int tx = sx + moveX[r];
                int ty = sy + moveY[r];

                if (!IsValid(tx, ty)) continue;

                if (Math.Abs(prev - r) == 2) continue;

                tempState = new Puzzle(state);

                int indexT = tx + ty * w;
                int indexS = sx + sy * w;

                state.MD -= MDT[indexT, state.f[indexT]];
                state.MD += MDT[indexS, state.f[indexT]];

                int temp = state.f[indexT];
                state.f[indexT] = state.f[indexS];
                state.f[indexS] = temp;

                state.space = indexT;

                if (DFS(state, depth + 1, r))
                {
                    path[depth] = r;
                    return true;
                }

                state = tempState;
            }
            return false;
        }

        private bool IsValid(int x, int y)
        {
            if (x < 0) return false;
            if (y < 0) return false;
            if (x >= w) return false;
            if (y >= h) return false;
            return true;
        }

        private int GetAllMD(Puzzle p)
        {
            int sum = 0;

            for (int i = 0; i < n; i++)
            {
                if (p.f[i] != 0) sum += MDT[i, p.f[i]];
            }
            return sum;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            StringBuilder sb = new StringBuilder();

            int h = 2, w = 4;
            int n = h * w;

            string input;

            while (!string.IsNullOrEmpty(input = Console.ReadLine()))
            {
                NPuzzle NP = new NPuzzle(h, w);
                Puzzle s = new Puzzle(n);

                int[] temp = Array.ConvertAll(input.Split(' '), int.Parse);

                for (int i = 0; i < n; i++)
                {
                    s.f[i] = temp[i];

                    if (s.f[i] == 0) s.space = i;
                }

                string path = NP.IterativeDeeping(s);
                int ans = path != null ? path.Length : 0;
                sb.AppendLine(ans.ToString());
            }
            Console.Write(sb);
        }
    }
}