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)

#include <stdio.h>
#include <iostream>
#include <cmath>
#include <cassert>
#include <string>
using namespace std;

#define N1 4
#define N2 16
#define LIMITMAX 100
//#define false 0
//#define true 1

struct PUZZLE
{
    int f[N2], kuuhaku, MD; /*マンハッタン距離*/
                            //int cost;
};

static const int dx_123[4] = {0, -1, 0, 1};         //４方向
static const int dy_123[4] = {1, 0, -1, 0};         //４方向
static const char houkou[4] = {'r', 'u', 'l', 'd'}; //右:right,　上:up,　左:left,　下:down

int ManhattanDistance[N2][N2];
PUZZLE jyoutai;
int limit; //深さのlimit
int miti[LIMITMAX];

int GetallManhattanDistance(PUZZLE);
bool dfs(int, int);
//int max(int, int);
//int min(int, int);
string iterative_deepning(PUZZLE); //反復深化

int main()
{

    int i, j, k;
    PUZZLE in;

    for (i = 0; i < N2; i++)
    {
        for (j = 0; j < N2; j++)
        {
            ManhattanDistance[i][j] = abs(i / N1 - j / N1) + abs(i % N1 - j % N1);
        }
    }

    for (i = 0; i < N2; i++)
    {
        cin >> in.f[i];
        if (in.f[i] == 0)
        {
            in.f[i] = N2;
            in.kuuhaku = i;
        }
    }

    string kotae = iterative_deepning(in);

    cout << kotae.size();
    cout << endl;

    return 0;
}

/*
  void  swap(int *a , int *b){
  int *tmp;
  
  tmp = a;
  a = b ;
  b = tmp;
  
  }
*/
int GetallManhattanDistance(PUZZLE p)
{ //全てのマンハッタン距離を取得する

    int goukei = 0;
    int i, j, k;

    for (i = 0; i < N2; i++)
    {
        if (p.f[i] == N2)
            continue;
        goukei += ManhattanDistance[i][p.f[i] - 1];
    }

    return goukei;
}

bool dfs(int depth, int prev)
{

    int i, j, k;
    int r;
    int sx, sy;
    PUZZLE tmp;
    int tx, ty;

    if (jyoutai.MD == 0)
        return true;
    //現在の深さにヒューリスティックを足して制限を超えたら枝を切る

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

    sx = jyoutai.kuuhaku / N1;
    sy = jyoutai.kuuhaku % N1;

    for (r = 0; r < 4; r++)
    {
        tx = sx + dx_123[r];
        ty = sy + dy_123[r];

        if (tx < 0 || tx >= N1 || ty < 0 || ty >= N1)
            continue;
        if (max(prev, r) - min(prev, r) == 2)
            continue;
        tmp = jyoutai;
        //マンハッタン距離の差分を計算しつつ、ピースをスワップ
        jyoutai.MD -= ManhattanDistance[tx * N1 + ty][jyoutai.f[tx * N1 + ty] - 1];
        jyoutai.MD += ManhattanDistance[sx * N1 + sy][jyoutai.f[tx * N1 + ty] - 1];
        swap(jyoutai.f[tx * N1 + ty], jyoutai.f[sx * N1 + sy]);
        jyoutai.kuuhaku = tx * N1 + ty;
        if (dfs(depth + 1, r))
        {
            miti[depth] = r;
            return true;
        }
        jyoutai = tmp;
    }

    return false;
}
/*
  int max(int a, int b){
  if(a<b) return b;
  return a;
  }

  int min(int a, int b){
  if(a<b) return a;
  return b;
  }
*/

string iterative_deepning(PUZZLE in)
{ //反復深化

    int i, j, k;
    //string  kotae = "";
    //char kotae2[] = "unsolvable";

    in.MD = GetallManhattanDistance(in); //初期のマンハッタン距離

    for (limit = in.MD; limit <= LIMITMAX; limit++)
    {
        jyoutai = in;
        if (dfs(0, -100))
        {
            string kotae = "";
            for (i = 0; i < limit; i++)
                kotae += houkou[miti[i]];
            return kotae;
        }
    }

    return "できませんでした";
}