Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

15 Puzzle

The goal of the 15 puzzle problem is to complete pieces on $4 \times 4$ cells where one of the cells is empty space.

In this problem, the space is represented by 0 and pieces are represented by integers from 1 to 15 as shown below.

1 2 3 4
6 7 8 0
5 10 11 12
9 13 14 15

You can move a piece toward the empty space at one step. Your goal is to make the pieces the following configuration in the shortest move (fewest steps).

1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 0

Write a program which reads an initial state of the puzzle and prints the fewest steps to solve the puzzle.

Input

The $4 \times 4$ integers denoting the pieces or space are given.

Output

Print the fewest steps in a line.

Constraints

The given puzzle is solvable in at most 45 steps.

Sample Input

1 2 3 4
6 7 8 0
5 10 11 12
9 13 14 15

Sample Output

8

Solution in C# (judge verdict: Accepted)

using System;

namespace ALDS1_13_C
{
    class Puzzle
    {
        internal int[] f;
        internal int space, MD;
        public Puzzle()
        {
            f = new int[16];
            space = 0;
            MD = 0;
        }
    }
    class Program
    {
        const int N = 4;
        const int N2 = 16;
        static int LIMIT = 45;
        static int limit;
        static int[,] MDT = new int[N2, N2];
        static int[] dx = { 0, -1, 0, 1 };
        static int[] dy = { 1, 0, -1, 0 };
        static Puzzle state = new Puzzle();
        static Puzzle P = new Puzzle();

        static void P_COPY(Puzzle x, Puzzle y)
        {
            x.f = (int[])y.f.Clone();
            x.space = y.space;
            x.MD = y.MD;
        }
        static bool DFS(int depth, int prev)
        {
            if (state.MD == 0) return true;
            if (depth + state.MD > limit) return false;

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

            var tmp = new Puzzle();
            for (int r = 0; r < 4; r++)
            {
                int tx = sx + dx[r];
                int ty = sy + dy[r];
                if (tx < 0 || ty < 0 || tx >= N || ty >= N) continue;
                if (Math.Abs(prev - r) == 2) continue;

                P_COPY(tmp, state);

                int T = tx * N + ty;
                int S = sx * N + sy;
                state.MD -= MDT[T, state.f[T] - 1];
                state.MD += MDT[S, state.f[T] - 1];

                int tt = state.f[T];
                state.f[T] = state.f[S];
                state.f[S] = tt;

                state.space = T;

                if (DFS(depth + 1, r)) return true;
  
                P_COPY(state, tmp);
            }
            return false;
        }
   
        static int GetAllMD()
        {
            int sum = 0;
            for (int i = 0; i < N2; i++)
            {
                if (P.f[i] == N2) continue;
                sum += MDT[i, P.f[i] - 1];
            }
            return sum;
        }
        static void IDA()
        {
            P.MD = GetAllMD();
            for (limit = P.MD; limit <= LIMIT ; limit++)
            {
                P_COPY(state, P);
                if(DFS(0, -45))
                {
                    Console.WriteLine(limit);
                    return;
                }
            }
        }
        static void Main(string[] args)
        {
            for (int i = 0; i < N2; i++)
            {
                for (int j = 0; j < N2; j++)
                {
                    MDT[i, j] = Math.Abs(i / N - j / N) + Math.Abs(i % N - j % N);
                }
            }       
            for (int i = 0; i < N; i++)
            {
                var t = scan;
                for (int j = 0; j < N; j++)
                {
                    var p = N * i + j;
                    P.f[p] = t[j];
                    if (t[j] == 0)
                    {
                        P.f[p] = N2;
                        P.space = p;
                    }
                }               
            }
            IDA();
        }
      
        static int[] scan { get { return Array.ConvertAll(Console.ReadLine().Split(), int.Parse); } }
    }
}