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;
using System.Collections.Generic;
using System.Linq;
using System.Text;

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

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

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

            space = other.space;
            MD = other.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 / h - j / w) + Math.Abs(i % h - 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] - 1];
                state.MD += MDT[indexS, state.f[indexT] - 1];

                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] != n) sum += MDT[i, p.f[i] - 1];
            }
            return sum;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            int h = 4, w = 4;
            int n = h * w;

            NPuzzle NP = new NPuzzle(h, w);
            Puzzle s = new Puzzle(n);

            for (int i = 0; i < h; i++)
            {
                int[] input = Array.ConvertAll(Console.ReadLine().Split(' '), int.Parse);

                for (int j = 0; j < w; j++)
                {
                    int index = i * w + j;
                    s.f[index] = input[j];

                    if (input[j] == 0)
                    {
                        s.f[index] = n;
                        s.space = index;
                    }
                }
            }

            string ans = NP.IterativeDeeping(s);

            Console.WriteLine(ans != null ? ans.Length : 0);
        }
    }
}