Problem:
11 パズル

太郎君は 8 パズルが大得意で休み時間などにいつも友達に並び替えてもらって遊んでいます。そんなとき、友達から「もっと複雑なパズルは解ける?」と聞かれたのですが、他のパズルはやったことはありません。どうやらその友達は自作で 11 パズルを作っていたみたいです。そのパズルは以下のような形をしています。

11 パズルは 11 枚の正方形のカードと、図 1 のような形の枠を使って行います。最初に 11 枚のカードを枠に入れます。すると 2 カ所の空きスペースができますので、この空きスペースに隣接したカードを動かすことができます。これを繰り返し、カードをきれいに整列して、図 2 の完成型にすることが 11 パズルの目的です。

太郎君はこのパズルに挑戦することにしました。ところが太郎君はこの 11 パズルをいとも簡単に解いてしまいました。そこで友達は「動かす数を一番少なくして解いてよ!」と無茶なことを言ってきました。太郎君は答えがわからないので、プログラムのできるあなたに 11 パズルを解くときの最小ステップ数を出すプログラムを作成してもらってから挑戦することにしました。このとき、2 カ所動かせるところがあるのですが、一つの数字を 1 スペース分移動させることを1ステップとして考えることとします。

11 パズルの初期状態を入力とし、11 パズルを解くときの最小ステップ数を出力するプログラムを作成してください。ただし、パズルを解くときの最小ステップ数が 20 ステップより多くかかってしまう場合は、「NA」と出力してください。パズルの状態は、一行目の情報から順に入力されるものとし、数字の 0 は空きスペースを表します。例えば、図 1 の状態を表す入力は以下のようになります。

6
2 1 3
10 5 7 0 8
9 4 11
0

Input

複数のデータセットの並びが入力として与えられます。入力の終わりは-1ひとつの行で示されます。 各データセットは以下の形式で与えられます。

p1
p2 p3 p4
p5 p6 p7 p8 p9
p10 p11 p12
p13

i 行目にパズルの i 行目の情報 pi (0 ≤ pi ≤ 11) が空白区切りで与えられます。

データセットの数は 100 を超えません。

Output

データセット毎に、最小ステップ数または NA を１行に出力します。

Sample Input

2
1 0 3
4 5 6 7 8
9 0 11
10
0
1 2 3
4 5 6 7 8
9 10 11
0
0
11 10 9
8 7 6 5 4
3 2 1
0
-1

Output for the Sample Input

2
0
NA

Solution in JAVA (judge verdict: Accepted)

import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Scanner;

public class Main {
	static HashMap<String,Integer> map = new HashMap<String,Integer>();
	static HashMap<String,Integer> map2 = new HashMap<String,Integer>();
	static int min = 21;
	static int[][] move = new int[][] {
								{2},
					   {2,5},{0,1,3,6},{2,7},
			   {5},{1,4,6,9},{2,5,7,10},{3,6,8,11},{7},
			          {5,10},{6,9,11,12},{7,10},
			          			{10}
			          };
 	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		String first = "0123456789AB0";
		Bfsa(0,0,12,first);
		IN:while(true) {
			min = 21;
			char[] data = new char[13];
			int xa = -1;
			int xb = -1;
			for(int i = 0; i < 13; i++) {
				String tmp = sc.next();
				if(tmp.equals("-1")) break IN;
				if(tmp.equals("10")) tmp = "A";
				if(tmp.equals("11")) tmp = "B";
				if(tmp.equals("0")) {
					if(xa == -1) xa = i;
					else xb = i;
				}
				data[i] = tmp.charAt(0);
			}
			if(map.containsKey(String.valueOf(data))) {
				min = map.get(String.valueOf(data));
			}
			Bfsb(0,xa,xb,String.valueOf(data));
			if(min <= 20) {
				System.out.println(min);
			}
			else {
				System.out.println("NA");
			}
			
		}
	}
	static ArrayDeque<Data> queue = new ArrayDeque<Data>();
	
	static void Bfsa(int a, int b, int c,String d) {
		queue.clear();
		queue.add(new Data(a,b,c,d));
		while(!queue.isEmpty()) {
			Data ax = queue.poll();
			bfsa(ax.a,ax.b1,ax.b2,ax.d);
		}
	}
	
	static void Bfsb(int a, int b, int c,String d) {
		map2.clear();
		System.gc();
		queue.clear();
		queue.add(new Data(a,b,c,d));
		while(!queue.isEmpty()) {
			Data ax = queue.poll();
			bfsb(ax.a,ax.b1,ax.b2,ax.d);
		}
	}
	
	
	static String swap(int a, int b, String c) {
		char[] x = c.toCharArray();
		char tmp = x[a];
		x[a] = x[b];
		x[b] = tmp;
		String cx = String.valueOf(x);
		return cx;
	}
	static void bfsa(int a, int b1,int b2, String c) {
		if(a > 10) return;
		if(!map.containsKey(c)) {
				map.put(c, a);
		}
		else {
			return;
		}
		for(int i = 0; i < 13; i++) {
			if(b1 == i) {
				for(int j = 0; j < move[i].length; j++) {
					if(move[i][j] == b2) {
						c = swap(b2,b1,c);
						queue.add(new Data(a,b2,b1,c));
						c = swap(b2,b1,c);
					}
					else {
						c = swap(move[i][j],b1,c);
						queue.add(new Data(a+1,move[i][j],b2,c));
						c = swap(move[i][j],b1,c);
					}
				}
			}
			if(b2 == i) {
				for(int j = 0; j < move[i].length; j++) {
					if(move[i][j] == b1) {
						c = swap(b2,b1,c);
						queue.add(new Data(a,b2,b1,c));
						c = swap(b2,b1,c);
					}
					else {
						c = swap(move[i][j],b2,c);
						queue.add(new Data(a+1,b1,move[i][j],c));
						c = swap(move[i][j],b2,c);
					}
				}
			}
		}
	}
	
	static void bfsb(int a, int b1,int b2, String c) {
		if(a > 10) return;
		if(!map2.containsKey(c)) {
			if(map.containsKey(c)) {
				min = Math.min(min, a + map.get(c));
			}
			map2.put(c, a);
		}
		else {
			return;
		}
		for(int i = 0; i < 13; i++) {
			if(b1 == i) {
				for(int j = 0; j < move[i].length; j++) {
					if(move[i][j] == b2) {
						c = swap(b2,b1,c);
						queue.add(new Data(a,b2,b1,c));
						c = swap(b2,b1,c);
					}
					else {
						c = swap(move[i][j],b1,c);
						queue.add(new Data(a+1,move[i][j],b2,c));
						c = swap(move[i][j],b1,c);
					}
				}
			}
			if(b2 == i) {
				for(int j = 0; j < move[i].length; j++) {
					if(move[i][j] == b1) {
						c = swap(b2,b1,c);
						queue.add(new Data(a,b2,b1,c));
						c = swap(b2,b1,c);
					}
					else {
						c = swap(move[i][j],b2,c);
						queue.add(new Data(a+1,b1,move[i][j],c));
						c = swap(move[i][j],b2,c);
					}
				}
			}
		}
	}
	
	static class Data {
		int a, b1, b2 ;
		String d;
		Data(int a, int b, int c, String d) {
			this.a = a;
			b1 = b;
			b2 = c;
			this.d = d;
		}
	}
	

}