Problem:
フロッピーキューブ

フロッピーキューブをプログラミングで解いてみましょう。フロッピーキューブは図のように表面に色のついた９個の立方体から構成されている立体パズルで、キューブの列を回転させることによって、６つの各面の色をそろえます。

フロッピーキューブに対しては下図のような４種類の操作を行うことができ、一回の操作で、端にある３つの隣接したキューブを１８０度回転することができます。わかりやすいように、図では、上面に＋(赤色)、下面に＊(緑色)、右前面に□(黄色)、左前面に●(青色)、右奥面に○(水色)、左奥面に■紫色) の記号が付いている状態を初期状態としています。

フロッピーキューブの初期状態が与えられるので、パズルを解くために必要な最小の操作回数を求めるプログラムを作成してください。

入力

入力は以下の形式で与えられる。

N
puzzle1
puzzle2
:
puzzleN

１行目のN (1 ≤ N ≤ 30) は操作回数を計算したいパズルの数である。続くN行に各フロッピーキューブの初期状態 puzzlei が与えられる。puzzlei は以下の形式で与えられる。

p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 p12 p13 p14 p15 p16 p17 p18 p19 p20 p21 p22 p23 p24 p25 p26 p27 p28 p29 p30

各フロッピーキューブの情報は 30 個の整数 pi (1 ≤ pi ≤ 6) からなる。pi は、下図のようにフロッピーキューブの各面に番号 i を振ったときの、そのキューブの面の色を表す。

パズルは、多くとも８回の操作で解くことができると仮定してよい。

出力

パズルごとに、最小の操作回数を１行に出力する。

入出力例

入力例

4
1 1 1 1 1 1 1 1 1 2 2 2 4 4 4 6 6 6 5 5 5 3 3 3 3 3 3 3 3 3
3 3 3 1 1 1 1 1 1 2 2 2 4 4 6 4 6 6 5 5 5 3 3 3 3 3 3 1 1 1
3 3 3 1 1 3 1 1 1 2 2 5 6 4 4 4 6 6 2 5 5 3 3 3 1 3 3 1 1 1
1 3 1 3 1 3 3 1 3 2 2 2 6 4 4 6 6 4 5 5 5 1 3 1 1 3 1 3 1 3

出力例

0
1
2
7

Solution in JAVA (judge verdict: Accepted)

import static java.util.Arrays.*;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;

public class Main {

	static void tr(Object... os) {
		System.err.println(deepToString(os));
	}
	void solve() {
		int n = sc.nextInt();
		for (int i = 0; i < n; i++) {
			int[] p = new int[30];
			for (int j = 0; j < 30; j++) p[j] = sc.nextInt();
			ans = 8;
			search(p, 0);
			System.out.println(ans);
		}
	}
	int ans;
	void search(int[] p, int depth) {
		if (goal(p)) {
			ans = Math.min(ans, depth);
			return;
		}
		if (depth + 1 >= ans) return;
		for (int i = 0; i < 4; i++) {
			f(p, op[i]);
			search(p, depth + 1);
			f(p, op[i]);
		}
	}

	void f(int[] p, int[][] o) {
		for (int i = 0; i < o.length; i++) {
			int a = o[i][0];
			int b = o[i][1];
			int t = p[a];
			p[a] = p[b];
			p[b] = t;
		}
	}

	boolean goal(int[] a) {
		int[][] is = {
			{0,1,2,3,4,5,6,7,8},
			{9,10,11},
			{12,13,14},
			{15,16,17},
			{18,19,20},
			{21,22,23,24,25,26,27,28,29}
		};
		for (int[] sub : is) {
			for (int i = 0; i < sub.length; i++) {
				if (a[sub[i]] != a[sub[0]]) return false;
			}
		}
		return true;
	}
	int[][][] op = {
		{{0,27},{1,28},{2,29},{14,15},{20,18}},
		{{0,23},{3,26},{6,29},{9,20},{15,17}},
		{{6,21},{7,22},{8,23},{12,17},{9,11}},
		{{2,21},{5,24},{8,27},{12,14},{11,18}},
	};

	public static void main(String[] args) throws Exception {
		new Main().run();
	}

	MyScanner sc = null;
	PrintWriter out = null;
	public void run() throws Exception {
		sc = new MyScanner(System.in);
		out = new PrintWriter(System.out);
		for (;sc.hasNext();) {
			solve();
			out.flush();
		}
		out.close();
	}

	class MyScanner {
		String line;
		BufferedReader reader;
		StringTokenizer tokenizer;

		public MyScanner(InputStream stream) {
			reader = new BufferedReader(new InputStreamReader(stream));
			tokenizer = null;
		}
		public void eat() {
			while (tokenizer == null || !tokenizer.hasMoreTokens()) {
				try {
					line = reader.readLine();
					if (line == null) {
						tokenizer = null;
						return;
					}
					tokenizer = new StringTokenizer(line);
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
		}
		public String next() {
			eat();
			return tokenizer.nextToken();
		}
		public String nextLine() {
			try {
				return reader.readLine();
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
		public boolean hasNext() {
			eat();
			return (tokenizer != null && tokenizer.hasMoreElements());
		}
		public int nextInt() {
			return Integer.parseInt(next());
		}
		public long nextLong() {
			return Long.parseLong(next());
		}
		public double nextDouble() {
			return Double.parseDouble(next());
		}
		public int[] nextIntArray(int n) {
			int[] a = new int[n];
			for (int i = 0; i < n; i++) a[i] = nextInt();
			return a;
		}
	}
}