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 <math.h>
#define N 4

int search(int,int,int,int,char);

int P[N][N];

int main(int argc, char *argv[])
{
  int md;
  int i, j, r, c, r_0, c_0, found;
  int res;

  for (i=0;i<N;i++) {
    for (j=0;j<N;j++)
      scanf("%d", &P[i][j]);
  }

  md = 0;
  for (i=0;i<N*N;i++) {
    found = 0;
    for (r=0;r<N;r++) {
      for (c=0;c<N;c++) {
    if (P[r][c] == i) {
      if (i == 0) {
        r_0 = r;
        c_0 = c;
      } else md += (int)fabs((i-1)/N - r) + (int)fabs((i-1)%N - c);
      found = 1;
      break;
    }
      }
      if (found == 1) break;
    }
  }

  for (i=0;;i+=2) {
    if ((r_0 + c_0) % 2 == 0) {
      if (md % 2 == 0) res = search(md,md+i, r_0, c_0, 'c');
      else res = search(md,md+i+1, r_0, c_0, 'c');
    }
    else {
      if (md % 2 == 0) res = search(md,md+i+1, r_0, c_0, 'c');
      else res = search(md,md+i, r_0, c_0, 'c');
    }

    if (res != -1) break;
  }

  printf("%d\n", res);

  return 0;
}

int search(int min,int limit, int r_0, int c_0, char mv)
{
  int md_c[4],op[4], num[4],res[4];
  int i;
  char dir[5] = "nswe";

  if (min == 0) return 0;

  for (i=0;i<4;i++) {
    md_c[i] = min;
    res[i] = -1;
  }
  op[0] = r_0-1;
  op[1] = r_0+1;
  op[2] = c_0-1;
  op[3] = c_0+1;

  if (op[0] >= 0) {
    if (mv != 's') {
      num[0] = P[op[0]][c_0];
      md_c[0] -= (int)fabs((num[0]-1)/N - op[0]);
      md_c[0] += (int)fabs((num[0]-1)/N - r_0);
    }
  }
  if (op[1] <= N-1) {
    if (mv != 'n') {
      num[1] = P[op[1]][c_0];
      md_c[1] -= (int)fabs((num[1]-1)/N - op[1]);
      md_c[1] += (int)fabs((num[1]-1)/N - r_0);
    }
  }
  if (op[2] >= 0) {
    if (mv != 'e') {
      num[2] = P[r_0][op[2]];
      md_c[2] -= (int)fabs((num[2]-1)%N - op[2]);
      md_c[2] += (int)fabs((num[2]-1)%N - c_0);
    }
  }
  if (op[3] <= N-1) {
    if (mv != 'w') {
      num[3] = P[r_0][op[3]];
      md_c[3] -= (int)fabs((num[3]-1)%N - op[3]);
      md_c[3] += (int)fabs((num[3]-1)%N - c_0);
    }
  }

  for (i=0;i<4;i++) {
    if (md_c[i] - min == -1) {
      if (i / 2 == 0) {
        P[op[i]][c_0] = 0;
        P[r_0][c_0] = num[i];
        res[i] = search(md_c[i], limit-1, op[i], c_0, dir[i]);
        if (res[i] == -1) {
          P[op[i]][c_0] = num[i];
          P[r_0][c_0] = 0;
        }
        else res[i]++;
      }
      else {
        P[r_0][op[i]] = 0;
        P[r_0][c_0] = num[i];
        res[i] = search(md_c[i], limit-1, r_0, op[i], dir[i]);
        if (res[i] == -1) {
          P[r_0][op[i]] = num[i];
          P[r_0][c_0] = 0;
        }
        else res[i]++;
      }
    }
    if (res[i] != -1) break;
  }

  for (i=0;i<4;i++) {
    if (md_c[i] - min == 1) {
      if (md_c[i] <= limit - 1) {
        if (i / 2 == 0) {
          P[op[i]][c_0] = 0;
          P[r_0][c_0] = num[i];
          res[i] = search(md_c[i], limit-1, op[i], c_0, dir[i]);
          if (res[i] == -1) {
            P[op[i]][c_0] = num[i];
            P[r_0][c_0] = 0;
          }
          else res[i]++;
        }
        else {
          P[r_0][op[i]] = 0;
          P[r_0][c_0] = num[i];
          res[i] = search(md_c[i], limit-1, r_0, op[i], dir[i]);
          if (res[i] == -1) {
            P[r_0][op[i]] = num[i];
            P[r_0][c_0] = 0;
          }
          else res[i]++;
        }
      }
      else res[i] = -1;
    }
  }
  if (res[0] == -1 && res[1] == -1 && res[2] == -1 && res[3] == -1) return -1;
  else if (res[0] != -1) return res[0];
  else if (res[1] != -1) return res[1];
  else if (res[2] != -1) return res[2];
  else return res[3];
}