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++11 (judge verdict: Time Limit Exceeded)

#include <bits/stdc++.h>
using namespace std;

const int N = 4;
const int LIMIT = 100;
int dx[4] = {0, 1, 0, -1}, dy[4] = {-1, 0, 1, 0};
int limit;
int puz[N*N];
int zero;
int esti;
int MDT[N*N][N*N];

int dfs(int dep, int pre) {
	if ( esti == 0 ) return dep;
	if ( dep >= limit ) return LIMIT;	

	int ret = LIMIT;
	for ( int i = 0; i < 4; i++ ) {
		if ( (i+2)%4 == pre ) continue;
		int y = zero/N, x = zero%N;
		int ny = y+dy[i], nx = x+dx[i];
		if ( ny < 0 || nx < 0 || ny >= N || nx >= N ) continue;
		int tmp[N*N];
		int tmp_zero  = zero;
		int tmp_esti = esti;		
		for ( int j = 0; j < N*N; j++ ) tmp[j] = puz[j];
		int ch_id = ny*N+nx;
		int ch_dat = puz[ch_id];		
		esti -= MDT[zero][N*N-1];
		esti -= MDT[ny*N+nx][ch_dat];
		esti += MDT[zero][ch_dat];
		esti += MDT[ny*N+nx][N*N-1];
		swap(puz[zero], puz[ch_id]);
		zero = ch_id;		
		ret = min(ret, dfs(dep+1, i));
		for ( int j = 0; j < N*N; j++ ) puz[j] = tmp[j];
		zero = tmp_zero;
		esti = tmp_esti;		
	}

	return ret;
}

int main() {
	for ( int i = 0; i < N*N; i++ ) {
		for ( int j = 0; j < N*N; j++ ) {
			MDT[i][j] = abs(i/N-j/N) + abs(i%N-j%N);            
		}
	}

	for ( int i = 0; i < N*N; i++ ) {		
		cin >> puz[i];
		if ( puz[i] == 0 ) {
			zero = i;
			puz[i] = N*N-1;			
		} else {
			puz[i]--;
		}
		esti += abs(i/N-puz[i]/N) + abs(i%N-puz[i]%N);        
	}

	for ( int i = esti; i <= LIMIT; i++ ) {
		limit = i;
		int ans = dfs(0, -1);
		if ( ans < 100 ) {
			cout << ans << endl;
			break;
		}
	}
	
	return 0;
}