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 <string.h>
#include <stdlib.h>

typedef unsigned long long ull;
typedef ull Puzzle;

#define get(a, i) (int)(((ull)(a) >> ((int)(i) * 4)) & 15)
#define set(a, i, v) (((ull)(a) & ~(15ull << ((int)(i) * 4))) | ((ull)(v) << ((int)(i) * 4)))

ull swap(ull a, int l, int r) {
	int lv = get(a, l);
	int rv = get(a, r);

	return set(set(a, l, rv), r, lv);
}


#define checkFinished(p) (p == 18364758544493064720ull)

int check(Puzzle p) {
	int i;
	for (i = 0; i < 16; ++i) {
		if (get(p, i) == 15)
			break;
	}

	int j, k, cnt = 0;
	Puzzle cp = p;
	for (j = 0; j < 16; ++j) {
		if (get(cp, j) == j)
			continue;

		for (k = j + 1; k < 16; ++k) {
			if (get(cp, k) != j)
				continue;

			cp = swap(cp, j, k);

			++cnt;

			break;
		}
	}

	return (cnt & 1) == (((i % 4 - 3) + (i / 4 - 3)) & 1);
}

int md(Puzzle p) {
	int i, cnt = 0;
	for (i = 0; i < 16; ++i) {
        if(get(p, i) == 15)
            continue;
		cnt += abs(get(p, i) / 4 - i / 4) + abs(get(p, i) % 4 - i % 4);
	}

	return cnt;
}

int id(Puzzle p) {
	int i, j, cnt = 0;
	for (i = 0; i < 16; ++i) {
		for (j = i + 1; j < 16; ++j) {
			if (get(p, i) > get(p, j))
				++cnt;
		}
	}

	return cnt / 3 + cnt % 3;
}

ull hash(int* p) {
	ull h = 0;
	int i;
	for (i = 0; i < 16; ++i) {
		h |= (ull)(p[i]) << (i * 4);
	}

	return h;
}

typedef struct {
	Puzzle p;
	int counter;
	int md;
	int prev;
} Node;
int last = 0;
Node heap[30000000];

void insert_heap(Node value) {
    int i = last++;

    while(i > 0) {
        int p = (i - 1) / 2;

        if(heap[p].md <= value.md)
            break;
        
        heap[i] = heap[p];
        i = p;
    }

    heap[i] = value;
}

void delete_heap() {
    Node x = heap[--last];

    int i = 0;
    while(i * 2 + 1 < last) {
        int a = i * 2 + 1, b = i * 2 + 2;

        if(b < last && heap[b].md < heap[a].md)
            a = b;

        if(heap[a].md >= x.md)
            break;

        heap[i] = heap[a];
        i = a;
    }
    heap[i] = x;
}


int dx[] = { 0, 1, 0, -1 };
int dy[] = { 1, 0, -1, 0 };

int main(void) {
	int i;
	char c;
    int v;
	int start[16];
	for (i = 0; i < 16; ++i) {
		scanf("%d", &v);

		if (v == 0 ) {
			start[i] = 15;
		}
		else {
			start[i] = v - 1;
		}
	}

	if (!check(hash(start))) {
		printf("impossible\n");

		return 0;
	}

	Node s;
	s.p = hash(start);
	s.counter = 0;
	s.md = md(s.p);
	s.prev = -1;

    insert_heap(s);

	while (last > 0) {
        Node s = heap[0];
        delete_heap();

		if (checkFinished(s.p)) {
			printf("%d\n", s.counter);
			//printf("%lu\n", que.size());

			return 0;
		}
		int t;
		for (t = 0; get(s.p, t) != 15; ++t);

		int i;
		for (i = 0; i < 4; ++i) {
			if (s.prev != -1 && (s.prev + 2) % 4 == i) {
				continue;
			}

			int ny = (t / 4) + dy[i];
			int nx = (t % 4) + dx[i];

			if (ny < 0 || ny >= 4 || nx < 0 || nx >= 4) {
				continue;
			}

			int newi = ny * 4 + nx;

			Node cand;
			//pushed %= 10000000;

			cand.p = s.p;
			cand.prev = i;
			cand.counter = s.counter + 1;

			cand.p = swap(cand.p, newi, t);

            /*int p = md(cand.p), q = id(cand.p);
            if(p < q) {
                p = q;
            }*/
			cand.md = cand.counter + md(cand.p);

            if(cand.md > 80)
                continue;

			/*if(cand.md > 44) {
				continue;
			}*/

			/*printf("%d %d %d\n", i, t, newi);*/

			//if (history.count(cand.p) == 0) {
			//	history.insert(cand.p);
            insert_heap(cand);
//				que.emplace(std::move(cand));
			//}
		}
	}


	/*for(i = 0; i < 16; ++i) {
		printf("%d ", start[i]);
	}*/
}