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: Runtime Error)

// AOJ ALDS1_13_C 15 Puzzle
// 2018.5.8 bal4u

#include <stdio.h>

typedef unsigned long long ull;

#define GOAL 0x123456789ABCDEF0LL
#define ABS(a) ((a)>=0?(a):-(a))

typedef struct {
	ull s;		// パズルの状態。4bitで数字１つに対応。計64bit
	char x;		// 0の位置（0-origin）
	char v;		// ステップ数
} TBL; TBL tbl[400000]; int sz;

int hmax, qmax;

int hi[16] = {2,3,3,2,3,4,4,3,3,4,4,3,2,3,3,2};
int to[16][4] = {
{1,4},{0,2,5},{1,3,6},{2,7},
{0,5,8},{1,4,6,9},{2,5,7,10},{3,6,11},
{4,9,12},{5,8,10,13},{6,9,11,14},{7,10,15},
{8,13},{9,12,14},{10,13,15},{11,14}};

double magic = 1;

// プライオリティ・キュー
#define QMAX 100000
typedef struct { int id; char t; } QUE;  // t:評価値
QUE que[QMAX]; int qsize;

#define PARENT(i) ((i)>>1)
#define LEFT(i)   ((i)<<1)
#define RIGHT(i)  (((i)<<1)+1)

void min_heapify(int i)
{
	int l, r;
	int min;

	l = LEFT(i), r = RIGHT(i);
	if (l < qsize && que[l].t < que[i].t) min = l; else min = i;
	if (r < qsize && que[r].t < que[min].t) min = r;
	if (min != i) {
		QUE t = que[i]; que[i] = que[min]; que[min] = t;
		min_heapify(min);
	}
}

void deq()
{
  que[0] = que[--qsize];
  min_heapify(0);
}

void enq(int id, int t)
{
	int i, min;
	QUE qt;

	i = qsize++;	if (qsize > qmax) qmax = qsize;
	que[i].id = id, que[i].t = t;
	while (i > 0 && que[min = PARENT(i)].t > que[i].t) {
		qt = que[i]; que[i] = que[min]; que[min] = qt;
		i = min;
	}
}

// ハッシュ関数
#define HASHSIZ 200003
typedef struct { ull s; int id; } HASH;
HASH hash[HASHSIZ+3], *hashend  = hash +HASHSIZ;

int lookup(ull s)
{
	HASH *p = hash + (int)(s % HASHSIZ);
	while (p->s) {
		if (p->s ==s) return tbl[p->id].v;
		if (++p == hashend) p = hash;
	}
	return -1;
}

void insert(ull s, int id)
{
	HASH *p = hash + (int)(s % HASHSIZ);
	while (p->s) {
		if (p->s == s) { tbl[p->id].v = tbl[id].v; return; }
		if (++p == hashend) p = hash;
	}
	p->s = s, p->id = id;
hmax++;
}

// 以上はライブラリ

// 状態を16バイト配列に戻す
void toArray(char *p16, ull s)
{
	int i;
	
	for (i = 15; i >= 0; i--) {
		p16[i] = s & 0xf, s >>= 4;
	}
}

// 0の位置を zero から nx に移動（0-origin)
ull swap(char *p16, int zero, int nx)
{
	int i;
	ull res;
	
	res = 0;
	for (i = 0; i < 16; i++) {
		res <<= 4;
		if      (i == zero) res |= p16[nx];
		else if (i == nx)   res |= p16[zero];
		else                res |= p16[i];
	}
	return res;
}

// 評価関数：ゴールまでのステップ数を推定
int eval(ull s)
{
	int i, r1, c1, r2, c2;
	int e, t;

	e = 0;
	for (i = 15; i >= 0; i--) {
		t = s & 0xf, s >>= 4;
		if (t--) {
			r1 = i >> 2, c1 = i & 3;
			r2 = t >> 2, c2 = t & 3;
			e += ABS(r1-r2) + ABS(c1-c2);
		}
	}
	return (int)(e*magic);	// magicは1～2の間
}

int main()
{
	int i, id, x, nx, v, nv, t;
	ull s, ns;
	char p16[16];

	s = 0; for (i = 0; i < 16; i++) {
		scanf("%d", &t);
		p16[i] = t, s <<= 4, s |= t;
		if (t == 0) x = i;
	}
	sz = 0;
	qsize = 0;
	t = eval(s);
	if      (t <= 22) magic = 1.12;
	else if (t <= 25) magic = 1.14;
	else              magic = 1.28;

	tbl[++sz].s = s, tbl[sz].x = x, tbl[sz].v = 0;
	enq(sz, eval(s));
	insert(s, sz);

	while (qsize) {
		id = que[0].id, deq();
		s = tbl[id].s, x = tbl[id].x, v = tbl[id].v;

		if (s == GOAL) break;
		if (lookup(s) < v) continue;

		toArray(p16, s);
		for (i = 0; i < hi[x]; i++) {
			nx = to[x][i], ns = swap(p16, x, nx), nv = v+1;

			tbl[++sz].s = ns, tbl[sz].x = nx, tbl[sz].v = nv;
			t = lookup(ns);
			if (t < 1 || nv < t) {
				tbl[++sz].s = ns, tbl[sz].x = nx, tbl[sz].v = nv;
				enq(sz, eval(ns)+v);
				insert(ns, sz);
			}
		}
	}
	printf("%d\n", v);
//printf("sz %d, hmax %d, qmax %d\n", sz, hmax, qmax);
	return 0;
}