Problem:
7 パズル

7 パズルは 8 つの正方形のカードとこれらのカードがぴたりと収まる枠で構成されています。それぞれのカードには、互いに区別できるように 0, 1, 2, ..., 7 と番号がつけられています。枠には、縦に 2 個、横に 4 個のカードを並べることができます。

7 パズルを始めるときには、まず枠にすべてのカードを入れます。枠のなかで 0 のカードだけは、上下左右に隣接するカードと位置を交換することができます。たとえば、枠の状態が図(a) のときに、0 のカードの右に隣接した、7 のカードと位置を交換すれば、図(b) の状態になります。あるいは、図(a) の状態から 0 のカードの下に隣接した 2 のカードと位置を交換すれば図(c) の状態になります。図(a) の状態で 0 のカードと上下左右に隣接するカードは 7 と 2 のカードだけなので、これ以外の位置の入れ替えは許されません。

ゲームの目的は、カードをきれいに整列して図(d) の状態にすることです。最初の状態を入力とし、カードをきれいに整列するまでに、必要な最小手数を出力するプログラムを作成してください。ただし、入力されたカードの状態からは図(d) の状態に移ることは可能であるとします。

入力データは、1 行に 8 つの数字が空白区切りで与えられます。これらは、最初の状態のカードの並びを表します。例えば、図(a) の数字表現は0 7 3 4 2 5 1 6 に、図(c) は 2 7 3 4 0 5 1 6 となります。

図(a) 0 7 3 4 2 5 1 6 の場合

図(b) 7 0 3 4 2 5 1 6 の場合

図(c) 2 7 3 4 0 5 1 6 の場合

図(d) 0 1 2 3 4 5 6 7 (最終状態)

Input

上記形式で複数のパズルが与えられます。入力の最後まで処理してください。
与えられるパズルの数は 1,000 以下です。

Output

各パズルについて、最終状態へ移行する最小手数を１行に出力してください。

Sample Input

0 1 2 3 4 5 6 7
1 0 2 3 4 5 6 7
7 6 5 4 3 2 1 0

Output for the Sample Input

0
1
28

Solution in JAVA (judge verdict: Time Limit Exceeded)

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

/**
 * AIZU 0121
 */
public class Main {
	
	private int x = 2;
	private int y = 4;
	private BitSet isVisit;

	private Main() {
		Scanner in = new Scanner(System.in);
		
		while(in.hasNext()) {
			byte[] puzzle = new byte[x*y];
			for(int i=0;i<x*y;i++) {
				puzzle[i] = in.nextByte();
			}
			isVisit = new BitSet();
			System.out.println(solve(puzzle));
		}
		in.close();	
	}
	
	// [0の座標番号][2~3個の交換候補の座標]
	final static int[][] MOVABLE_PAIRS = {
		{1,4}, {0,2,5}, {1,3,6}, {2,7},
		{0,5}, {1,4,6}, {2,5,7}, {3,6}
	};
	
	public class Puzzle {
		// 座標番号
		// 0 1 2 3
		// 4 5 6 7		
		final byte[] state; // パズルの状態
		
		final int depth; // 深さ(操作回数)
		final Puzzle parent; // 親状態（デバッグ用）

		final int movablePiecePoint; // パズル内にある動かせるピースの座標 
		final int stateCode; // 状態で一意に決まるindex(枝狩り用)
		
		protected Puzzle (int depth, byte[] state, Puzzle parent){
			this.depth = depth;
			this.state = state;
			this.parent = parent;
			
			// 0(動かせるピース)の座標を探索
			int tmp = 0;
			for(int i=0;i<x*y;i++) {
				if(state[i]==0) {
					tmp = i;
					break;
				}
			}
			this.movablePiecePoint = tmp;
			
			// 状態コードの計算
			int index = 0;
			for(int i=0;i<x*y;i++) {
				index += (Math.pow(10, i)*state[i]);
			}
			this.stateCode = index;
		}
		
		/**
		 * 完成形になったかのチェック
		 * @return 完成していればtrue
		 */
		private boolean check() {
			for(int i=0;i<x*y;i++) {
				if(this.state[i] != i) {
						return false;
				}
			}
			return true;
		}
		
		/**
		 * 次の状態を生成する
		 * @param point1,point2 交換するピースの位置番号
		 * @return 移動後の状態を表す配列
		 */
		protected byte[] move(int point1, int point2) {
			byte[] nextState = Arrays.copyOf(this.state, x*y);
			byte tmp = nextState[point1];
			nextState[point1] = nextState[point2];
			nextState[point2] = tmp;
			return nextState;
		}
		
		public String toString() {
			StringBuilder str = new StringBuilder("");
			for(int n : state) {
				str.append(n);
			}
			return str.toString();
		}
	}
	
	/**
	 * パズルを解く
	 * @param puzzle 初期状態
	 * @return 操作回数
	 */
	private String solve(byte[] puzzle) {
		ArrayDeque<Puzzle> queue = new ArrayDeque<Puzzle>();
		queue.add(new Puzzle(0, puzzle, null));
		Puzzle now;
		while(queue.size()>0) {
			// キューの先頭の状態を取り出し,現在の状態を更新
			now = queue.poll();

			// 完成したかの確認
			if(now.check()) {
				return ""+now.depth;
			}

			if(!isVisit.get(now.stateCode)) {
				// 現在の状態から1移動で生成される次の状態をすべて生成し,キューに入れる.						
				for(int nextMove : MOVABLE_PAIRS[now.movablePiecePoint]) {
					queue.add(new Puzzle(now.depth+1, now.move(now.movablePiecePoint,nextMove), now));
				}
			}

			isVisit.set(now.stateCode, true);
		}
		return "";
	}
	
	public static void main(String[] args) {
		new Main();
	}

}