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: Memory Limit Exceeded)

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.HashSet;
import java.util.NoSuchElementException;
import java.util.Queue;

public class Main {
	HashSet<Integer>[] set;
	int[] dy = {0,0,1,-1};
	int[] dx = {1,-1,0,0};
	private class P{
		int x,y;
		public P(int x,int y){
			this.x = x;
			this.y = y;
		}
	}
	@SuppressWarnings("unchecked")
	public void solve() {
		while(hasNext()){
			int n = 0;
			for(int i = 0;i < 8;i++){
				int m = nextInt();
				for(int j = 7 - i;j > 0;j--){
					m *= 10;
				}
				n += m;
			}
			Queue<P> q = new ArrayDeque<P>();
			set = new HashSet[10000];
			for(int i = 0;i < 10000;i++){
				set[i] = new HashSet<Integer>();
			}
			q.add(new P(n,0));
			while(q.size() > 0){
				P p = q.poll();

				int x = p.x;
				int y = p.y;

				String s = String.valueOf(x);
				String s1 = s.substring(0,4);
				String s2 = s.substring(4);
				int z1 = Integer.parseInt(s1);
				int z2 = Integer.parseInt(s2);
				if(set[z1].contains(z2))continue;
				set[z1].add(z2);
				if(x == 1234567){
					out.println(y);
					break;
				}

				int[][] a = new int[2][4];
				int py = 0;
				int px = 0;
				for(int i = 7;i >= 0;i--){
					a[i / 4][i % 4] = x % 10;
					if(a[i / 4][i % 4] == 0){
						py = i / 4;
						px = i % 4;
					}
					x/=10;
				}
				for(int i = 0;i < 4;i++){
					int ny = py + dy[i];
					int nx = px + dx[i];
					if(ny < 0 || nx < 0 || ny >= 2 || nx >= 4)continue;
					int tmp = a[py][px];
					a[py][px] = a[ny][nx];
					a[ny][nx] = tmp;
					int m = 0;
					for(int j = 0;j < 8;j++){
						int b = a[j / 4][j % 4];
						for(int k = 7 - j;k > 0;k--){
							b *= 10;
						}
						m += b;
					}
					q.add(new P(m,y + 1));
					tmp = a[py][px];
					a[py][px] = a[ny][nx];
					a[ny][nx] = tmp;
				}
			}
		}
	}

	public static void main(String[] args) {
		out.flush();
		new Main().solve();
		out.close();
	}

	/* Input */
	private static final InputStream in = System.in;
	private static final PrintWriter out = new PrintWriter(System.out);
	private final byte[] buffer = new byte[2048];
	private int p = 0;
	private int buflen = 0;

	private boolean hasNextByte() {
		if (p < buflen)
			return true;
		p = 0;
		try {
			buflen = in.read(buffer);
		} catch (IOException e) {
			e.printStackTrace();
		}
		if (buflen <= 0)
			return false;
		return true;
	}

	public boolean hasNext() {
		while (hasNextByte() && !isPrint(buffer[p])) {
			p++;
		}
		return hasNextByte();
	}

	private boolean isPrint(int ch) {
		if (ch >= '!' && ch <= '~')
			return true;
		return false;
	}

	private int nextByte() {
		if (!hasNextByte())
			return -1;
		return buffer[p++];
	}

	public String next() {
		if (!hasNext())
			throw new NoSuchElementException();
		StringBuilder sb = new StringBuilder();
		int b = -1;
		while (isPrint((b = nextByte()))) {
			sb.appendCodePoint(b);
		}
		return sb.toString();
	}

	public int nextInt() {
		return Integer.parseInt(next());
	}

	public long nextLong() {
		return Long.parseLong(next());
	}

	public double nextDouble() {
		return Double.parseDouble(next());
	}
}