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: Time Limit Exceeded)

#include <stdio.h>

#define N 16

int board[N];
int rows = 4, cols = 4, zeroIndex;

// for previousMove: 0 is down, 1 is up, 2 is left, 3 is right
int blindSearch(int x, int y, int moves, int previousMove) {
  int i, foundAnswer;

  // answer is less than manhattan distance, not possible
  if (moves < (x + y))
    return 0;

  if (!moves) {
    for (i = 0; i < N - 1; i++) {
      if (board[i] != i + 1)
        return 0;
    }

    return 1;
  }

  if (x > 0 && previousMove != 1) {
    // can expand down
    board[zeroIndex] = board[zeroIndex + rows];
    zeroIndex += rows;

    foundAnswer = blindSearch(x - 1, y, moves - 1, 0);
    if (foundAnswer)
      return 1;

    board[zeroIndex] = board[zeroIndex - rows];
    zeroIndex -= rows;
  }

  if (y > 0 && previousMove != 3) {
    // right
    board[zeroIndex] = board[zeroIndex + 1];
    zeroIndex++;

    foundAnswer = blindSearch(x, y - 1, moves - 1, 2);
    if (foundAnswer)
      return 1;

    board[zeroIndex] = board[zeroIndex - 1];
    zeroIndex--;
  }

  if (y < rows - 1 && previousMove != 2) {
    // left
    board[zeroIndex] = board[zeroIndex - 1];
    zeroIndex--;

    foundAnswer = blindSearch(x, y + 1, moves - 1, 3);
    if (foundAnswer)
      return 1;

    board[zeroIndex] = board[zeroIndex + 1];
    zeroIndex++;
  }

  if (x < cols - 1 && previousMove != 0) {
    // up
    board[zeroIndex] = board[zeroIndex - rows];
    zeroIndex -= rows;

    foundAnswer = blindSearch(x + 1, y, moves - 1, 1);
    if (foundAnswer)
      return 1;

    board[zeroIndex] = board[zeroIndex + rows];
    zeroIndex += rows;
  }

  return 0;
}

int main() {
  int i, x, y, current;

  for (i = 0; i < N; i++) {
    scanf("%d", &board[i]);
    if (!board[i])
      zeroIndex = i;
  }

  x = cols - (zeroIndex / rows) - 1;
  y = rows - (zeroIndex % cols) - 1;

  for (current = 0; current < 50; current++) {
    if (blindSearch(x, y, current, -1)) {
      printf("%d\n", current);
      return 0;
    }
  }
}