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.*;
import java.util.regex.Pattern;
public class Main {
	
	ArrayList<ArrayList<Integer>> swapList;
	int ans;
	HashMap<String,Integer> fromAns;
	
	class C{
		int s;
		String now;
		public C(String now, int s){
			this.now = now;
			this.s = s;
		}
	}
	
	private void doit(){
		Scanner sc = new Scanner(System.in);
		
		//swap pattern list
		createSwapList();
		
		//from ans
		String goal = "0 1 2 3 4 5 6 7 8 9 10 11 0";
		fromAns = new HashMap<String, Integer>();
		createStep(goal,0);
		
		while(true){
			//input data
			int n = sc.nextInt();
			if(n == -1) break;
			//create start String
			StringBuilder sb  = new StringBuilder(""+n);
			for(int i=1; i <= 12; i++){
				sb.append(" ");
				sb.append(sc.next());
			}
			String startS = sb.toString();
			
			if(fromAns.containsKey(startS)){
				System.out.println(fromAns.get(startS));
				continue;
			}
			
			//from start
			ans = -1;
			createStep(startS,1);
			
			//comp and out
			if(ans != -1){
				System.out.println(ans);
			}
			else{
				System.out.println("NA");
			}
		}
//		for(String key: fromAns.keySet()){
//			if(fromAns.get(key) == 10){
//				System.out.println(key);
//			}
//		}
	}
	
	private int getInd0F(String [] s) {
		int len = s.length;
		for(int i=0; i < len; i++){
			if(s[i].equals("0")) return i;
		}
		return -1;
	}
	
	private int getInd0L(String [] s) {
		int len = s.length;
		for(int i=len-1; i >= 0; i--){
			if(s[i].equals("0")) return i;
		}
		return -1;
	}
	
	private String createS(String [] s){
		StringBuilder sb = new StringBuilder();
		for(int i=0; i < s.length-1; i++){
			sb.append(s[i]);
			sb.append(" ");
		}
		sb.append(s[s.length-1]);
		return sb.toString();
	}
	
	private void createStep(String start, int state){
		//init
		LinkedList<C> open = new LinkedList<C>();
		open.add(new C(start, 0));
		HashMap<String, Integer> close = new HashMap<String, Integer>();
		if(fromAns.containsKey(start)){
			ans = fromAns.get(start);
			return ;
		}
		close.put(start, 0);
		
		//start
		while(! open.isEmpty()){
			C now = open.removeFirst();
			
			//find a zero ind
			String [] nowParse = now.now.split(" ");
			int ind01 = getInd0F(nowParse);
			int ind02 = getInd0L(nowParse);
			int [] ind0list = {ind01, ind02};
			
			//swap pattern times
			for(int i = 0; i < ind0list.length;i++){
				int nowind = ind0list[i];
				for(int j=0; j < swapList.get(nowind).size(); j++){
					int swapind = swapList.get(nowind).get(j);
					String [] work = now.now.split(" ");
					
					//swap
					String temp = work[nowind];
					work[nowind] = work[swapind];
					work[swapind] = temp;
					
					//create new String 
					String newS = createS(work);
					
					//close contains
					if(close.containsKey(newS)) continue;
					
					//find a goal
					int nextstep = now.s + 1;
					if(fromAns.containsKey(newS)){
						ans = nextstep + fromAns.get(newS);
						return ;
					}
					
					//open.add
					if(nextstep != 10){
						open.add(new C(newS, nextstep));
					}
					
					//close.put
					close.put(newS, nextstep);
				}
			}
		}
		if(state == 0){
			fromAns = close;
		}
	}

	private void createSwapList() {
		swapList = new ArrayList<ArrayList<Integer>>();
		for(int i=0; i <= 12; i++){
			swapList.add(new ArrayList<Integer>());
		}
		for(int i=0; i <= 12; i++){
			//bottom
			if(i == 1 || i == 2 || i == 3 || i == 5 || i == 6 || i == 7){
				swapList.get(i).add(i+4);
				swapList.get(i+4).add(i);
			}
			if(i == 0 || i == 10){
				swapList.get(i).add(i+2);
				swapList.get(i+2).add(i);
			}
			//right
			if(i == 1 || i == 2 || i == 4 || i == 5 || i == 6 || i == 7 || i == 9 || i == 10 ){
				swapList.get(i).add(i+1);
				swapList.get(i+1).add(i);
			}
		}
	}

	public static void main(String[] args) {
		Main obj = new Main();
		obj.doit();
	}
}