Problem:
Problem F: Dice Puzzle

Let’s try a dice puzzle. The rules of this puzzle are as follows.

Dice with six faces as shown in Figure 1 are used in the puzzle.

Figure 1: Faces of a die

With twenty seven such dice, a 3 × 3 × 3 cube is built as shown in Figure 2.

Figure 2: 3 × 3 × 3 cube

When building up a cube made of dice, the sum of the numbers marked on the faces of adjacent dice that are placed against each other must be seven (See Figure 3). For example, if one face of the pair is marked “2”, then the other face must be “5”.

Figure 3: A pair of faces placed against each other

The top and the front views of the cube are partially given, i.e. the numbers on faces of
some of the dice on the top and on the front are given.

Figure 4: Top and front views of the cube

The goal of the puzzle is to find all the plausible dice arrangements that are consistent
with the given top and front view information.

Your job is to write a program that solves this puzzle.

Input

The input consists of multiple datasets in the following format.

N
Dataset1
Dataset2
...
DatasetN

N is the number of the datasets.

The format of each dataset is as follows.

T11 T12 T13
T21 T22 T23
T31 T32 T33
F11 F12 F13
F21 F22 F23
F31 F32 F33

Tij and Fij (1 ≤ i ≤ 3, 1 ≤ j ≤ 3) are the faces of dice appearing on the top and front views,
as shown in Figure 2, or a zero. A zero means that the face at the corresponding position is
unknown.

Output

For each plausible arrangement of dice, compute the sum of the numbers marked on the nine
faces appearing on the right side of the cube, that is, with the notation given in Figure 2,

∑3i=1∑3j=1Rij.

For each dataset, you should output the right view sums for all the plausible arrangements, in
ascending order and without duplicates. Numbers should be separated by a single space.

When there are no plausible arrangements for a dataset, output a zero.

For example, suppose that the top and the front views are given as follows.

Figure 5: Example

There are four plausible right views as shown in Figure 6. The right view sums are 33, 36, 32,
and 33, respectively. After rearranging them into ascending order and eliminating duplicates,
the answer should be “32 33 36”.

Figure 6: Plausible right views

The output should be one line for each dataset. The output may have spaces at ends of lines.

Sample Input

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

Output for the Sample Input

27
24
32 33 36
0

Solution in JAVA (judge verdict: Accepted)

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Scanner;
import java.util.Set;

//Dice Puzzle
public class Main{

	static class Dice <T>{
		public T[] id;
			enum Face{TOP, BOTTOM, FRONT, BACK, RIGHT, LEFT};
			public T get(Face f){
				return id[f.ordinal()];
			}
			public Dice<T> copy(){
				return new Dice<T>(id[0], id[1], id[2], id[3], id[4], id[5]);
			}
			public Dice() {
				@SuppressWarnings("unchecked")
				T[] tid = (T[])new Object[6];
				id = tid;
			}
			public Dice(T top, T bottom, T front, T back, T right, T left) {
				@SuppressWarnings("unchecked")
				T[] tid = (T[])new Object[6];
				id = tid;
				id[Face.TOP.ordinal()] = top;
				id[Face.BOTTOM.ordinal()]= bottom;
				id[Face.FRONT.ordinal()] = front;
				id[Face.BACK.ordinal()] = back;
				id[Face.RIGHT.ordinal()] = right;
				id[Face.LEFT.ordinal()] = left;
			}
			//true: Xツ篠イツ陛サツ古シツづ可偲ィツ前ツづ可転ツつェツつキ
			//false: Xツ篠イツ陛サツ古シツづ可可慊づ可転ツつェツつキ
			void rollX(boolean isReverse) {
				if(!isReverse) roll(Face.TOP, Face.FRONT, Face.BOTTOM, Face.BACK);
				else roll(Face.TOP, Face.BACK, Face.BOTTOM, Face.FRONT);
			}
			//true: Yツ篠イツ陛サツ古シツづ可債カツづ鳴転ツつェツつキ
			//false: Yツ篠イツ陛サツ古シツづ可右ツづ鳴転ツつェツつキ
			void rollY(boolean isReverse) {
				if(!isReverse) roll(Face.TOP, Face.LEFT, Face.BOTTOM, Face.RIGHT);
				else roll(Face.TOP, Face.RIGHT, Face.BOTTOM, Face.LEFT);
			}
			//true: Zツ篠イツ陛サツ古シツづ可右ツづ鳴嘉アツつキ
			//false: Zツ篠イツ陛サツ古シツづ可債カツづ鳴嘉アツつキ
			void rollZ(boolean isReverse) {
				if(!isReverse) roll(Face.FRONT, Face.LEFT, Face.BACK, Face.RIGHT);
				else roll(Face.FRONT, Face.RIGHT, Face.BACK, Face.LEFT);
			}
			private void roll(Face w, Face x, Face y, Face z) {
				T tmp = id[w.ordinal()];
				id[w.ordinal()] = id[x.ordinal()];
				id[x.ordinal()] = id[y.ordinal()];
				id[y.ordinal()] = id[z.ordinal()];
				id[z.ordinal()] = tmp;
			}
			@Override
			public boolean equals(Object o) {
				if(!(o instanceof Dice<?>))return false;
				@SuppressWarnings("unchecked")
				Dice<T> d = (Dice<T>)o;
				for(Face f : Face.values()){
					if(!id[f.ordinal()].equals(d.id[f.ordinal()])){
						return false;
					}
				}
				return true;
			}
			List<Dice<T>> getAllState(){
				List<Dice<T>> lst = new ArrayList<Dice<T>>();
				for(int i = 0; i < 6; i++){
					for(int j = 0; j < 4; j++){
						lst.add(new Dice<T>(id[Face.TOP.ordinal()], id[Face.BOTTOM.ordinal()], id[Face.FRONT.ordinal()], id[Face.BACK.ordinal()], id[Face.RIGHT.ordinal()], id[Face.LEFT.ordinal()]));
						rollZ(false);
					}
					if(i%2 == 1) rollY(false);
					else rollX(false);
				}
				return lst;
			}
	}
	
	Dice<Integer>[] dice;
	int[][] top, front;
	Dice<Integer>[][][] a;
	Set<Integer> res;
	int[][] move = {
			{-1,0,0},
			{0,-1,0},
			{0,0,-1}
	};
	
	void dfs(int i, int j, int k){
		if(j==3){
			int sum = 0;
			for(int y=0;y<3;y++)for(int z=0;z<3;z++)sum+=a[2][y][z].get(Dice.Face.RIGHT);
			res.add(sum);
			return;
		}
		for(int x=0;x<24;x++){
			Dice<Integer> d = dice[x];
			if(k==0&&top[j][i]!=0&&d.get(Dice.Face.TOP)!=top[j][i])continue;
			if(j==2&&front[k][i]!=0&&d.get(Dice.Face.FRONT)!=front[k][i])continue;
			boolean ok = true;
			for(int m=0;m<3;m++){
				int ni = i+move[m][0], nj = j+move[m][1], nk = k+move[m][2];
				if(0<=ni&&ni<3&&0<=nj&&nj<3&&0<=nk&&nk<3){
					if(m==0){
						if(a[i-1][j][k].get(Dice.Face.RIGHT)+d.get(Dice.Face.LEFT)!=7){
							ok = false; break;
						}
					}
					if(m==1){
						if(a[i][j-1][k].get(Dice.Face.FRONT)+d.get(Dice.Face.BACK)!=7){
							ok = false; break;
						}
					}
					if(m==2){
						if(a[i][j][k-1].get(Dice.Face.BOTTOM)+d.get(Dice.Face.TOP)!=7){
							ok = false; break;
						}
					}
				}
			}
			if(!ok)continue;
			a[i][j][k] = d;
			if(i==2&&k==2){
				dfs(0, j+1, 0);
			}
			else if(i==2){
				dfs(0, j, k+1);
			}
			else dfs(i+1, j, k);
		}
	}
	
	@SuppressWarnings("unchecked")
	void run(){
		Dice<Integer> d = new Dice<Integer>(1, 6, 2, 5, 3, 4);
		dice = new Dice[24];
		int id = 0;
		for(Dice<Integer> x:d.getAllState())dice[id++] = x;
		Scanner sc = new Scanner(System.in);
		int T = sc.nextInt();
		while(T--!=0){
			top = new int[3][3]; front = new int[3][3];
			for(int i=0;i<3;i++)for(int j=0;j<3;j++)top[i][j] = sc.nextInt();
			for(int i=0;i<3;i++)for(int j=0;j<3;j++)front[i][j] = sc.nextInt();
			a = new Dice[3][3][3];
			res = new HashSet<Integer>();
			dfs(0, 0, 0);
			if(res.isEmpty())System.out.println(0);
			else{
				PriorityQueue<Integer> q = new PriorityQueue<Integer>();
				for(int x:res)q.add(x);
				System.out.print(q.poll());
				while(!q.isEmpty())System.out.print(" "+q.poll());
				System.out.println();
			}
		}
	}
	
	public static void main(String[] args) {
		new Main().run();
	}
}