Problem:
Problem J:
Cubic Colonies
In AD 3456, the earth is too small for hundreds of billions of people to live in peace. Interstellar Colonization Project with Cubes (ICPC) is a project that tries to move people on the earth to space colonies to ameliorate the problem. ICPC obtained funding from governments and manufactured space colonies very quickly and at low cost using prefabricated cubic blocks.
The largest colony looks like a Rubik's cube. It consists of 3 × 3 × 3 cubic blocks (Figure J.1A). Smaller colonies miss some of the blocks in the largest colony.
When we manufacture a colony with multiple cubic blocks, we begin with a single block. Then we iteratively glue a next block to existing blocks in a way that faces of them match exactly. Every pair of touched faces is glued.
Figure J.1: Example of the largest colony and a smaller colony
However, just before the first launch, we found a design flaw with the colonies. We need to add a cable to connect two points on the surface of each colony, but we cannot change the inside of the prefabricated blocks in a short time. Therefore we decided to attach a cable on the surface of each colony. If a part of the cable is not on the surface, it would be sheared off during the launch, so we have to put the whole cable on the surface. We would like to minimize the lengths of the cables due to budget constraints. The dashed line in Figure J.1B is such an example.
Write a program that, given the shape of a colony and a pair of points on its surface, calculates the length of the shortest possible cable for that colony.
Input
The input contains a series of datasets. Each dataset describes a single colony and the pair of the points for the colony in the following format.
x
1
y
1
z
1
x
2
y
2
z
2
b
0,0,0
b
1,0,0
b
2,0,0
b
0,1,0
b
1,1,0
b
2,1,0
b
0,2,0
b
1,2,0
b
2,2,0
b
0,0,1
b
1,0,1
b
2,0,1
b
0,1,1
b
1,1,1
b
2,1,1
b
0,2,1
b
1,2,1
b
2,2,1
b
0,0,2
b
1,0,2
b
2,0,2
b
0,1,2
b
1,1,2
b
2,1,2
b
0,2,2
b
1,2,2
b
2,2,2
(
x
1
,
y
1
,
z
1
) and (
x
2
,
y
2
,
z
2
) are the two distinct points on the surface of the colony, where
x
1
,
x
2
,
y
1
,
y
2
,
z
1
,
z
2
are integers that satisfy 0 ≤
x
1
,
x
2
,
y
1
,
y
2
,
z
1
,
z
2
≤ 3.
b
i,j,k
is '
#
' when there is a cubic block whose two diagonal vertices are (
i
,
j
,
k
) and (
i
+ 1,
j
+ 1,
k
+ 1), and
b
i,j,k
is '
.
' if there is no block. Figure J.1A corresponds to the first dataset in the sample input, whereas Figure J.1B corresponds to the second. A cable can pass through a zero-width gap between two blocks if they are touching only on their vertices or edges. In Figure J.2A, which is the third dataset in the sample input, the shortest cable goes from the point A (0, 0, 2) to the point B (2, 2, 2), passing through (1, 1, 2), which is shared by six blocks. Similarly, in Figure J.2B (the fourth dataset in the sample input), the shortest cable goes through the gap between two blocks not glued directly. When two blocks share only a single vertex, you can put a cable through the vertex
...(truncated)

Submitted solutions:

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 10005

enum DIR{
	UP,
	East,
	North,
	West,
	South,
	Down,
};


struct LOC{
	void set(int arg_X,int arg_Y,int arg_Z){
		X = arg_X;
		Y = arg_Y;
		Z = arg_Z;
	}
	/*void debug(){

		printf("X:%d Y:%d Z:%d\n",X,Y,Z);
	}*/
	int X,Y,Z;
};


struct Point3D{
	Point3D(double arg_x,double arg_y,double arg_z){
		x = arg_x;
		y = arg_y;
		z = arg_z;
		X = Y = Z = 0;
	}

	Point3D(){
		x = y = z = 0.0;
		X = Y = Z = 0;
	}

	Point3D operator + (Point3D p){ return Point3D(x+p.x,y+p.y,z+p.z); }
	Point3D operator - (Point3D p){ return Point3D(x-p.x,y-p.y,z-p.z);}
	Point3D operator * (double a){ return Point3D(a*x,a*y,a*z); }
	Point3D operator / (double a){ return Point3D(x/a,y/a,z/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y + z*z; }

	bool operator<(const Point3D &p) const{
		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else if(fabs(y-p.y) > EPS){

			return y < p.y;
		}else{

			return z < p.z;
		}
	}

	void set(int arg_X,int arg_Y,int arg_Z){
		X = arg_X;
		Y = arg_Y;
		Z = arg_Z;
	}

	void copy(){
		x = X;
		y = Y;
		z = Z;
	}

	bool operator == (const Point3D &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS && fabs(z-p.z) < EPS;
	}
	/*void debug(){

		printf("(%.3lf,%.3lf,%.3lf)\n",x,y,z);
	}*/
	int X,Y,Z;
	double x,y,z;
};

typedef Point3D Vector3D;

struct Line{
	Line(){

	}
	Line(Point3D a,Point3D b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point3D p[2];
};

struct Data{
	Data(){

		X = Y = Z = 0;
		x = y = z = 0;
	}
	Data(double arg_x,double arg_y,double arg_z){
		x = arg_x;
		y = arg_y;
		z = arg_z;
		X = Y = Z = 0;
	}

	void set(int arg_X,int arg_Y,int arg_Z){
		X = arg_X;
		Y = arg_Y;
		Z = arg_Z;
	}
	void copy(){
		x = X;
		y = Y;
		z = Z;
	}
	void debug(){

		printf("%d %d %d\n",X,Y,Z);
	}
	int X,Y,Z;
	double x,y,z;
};

struct Seg{
	void set(int arg_A,int arg_B){
		A = arg_A;
		B = arg_B;
	}
	int A,B;
};

struct Edge{
	Edge(int arg_to,double arg_dist){
		to = arg_to;
		dist = arg_dist;
	}
	int to;
	double dist;
};

struct Info{
	Info(){
		index = 0;
	}
	Info(Point3D arg_p,int arg_index){
		p = arg_p;
		index = arg_index;
	}
	bool operator<(const struct Info &arg)const{

		return p < arg.p;
	}
	bool operator==(const struct Info &arg) const{

		return p == arg.p;
	}
	Point3D p;
	int index;
};

struct State{
	State(int arg_node_id,double arg_sum_dist){
		node_id = arg_node_id;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct State  &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}
	int node_id;
	double sum_dist;
};

int num_loc,num_data,num_POINT,num_seg;
int S,T;
int ADJ[27][6];
int loc_X[6] = {0,1,0,-1,0,0},loc_Y[6] = {-1,0,0,0,0,1},loc_Z[6] = {0,0,1,0,-1,0};
int D_X[8] = {0,1,0,1,0,1,0,1},D_Y[8] = {0,0,0,0,1,1,1,1},D_Z[8] = {0,0,1,1,0,0,1,1};
int have_L[6][4] ={{0,1,2,3},{1,5,9,10},{2,6,10,11},{3,7,8,11},{0,4,8,9},{4,5,6,7}};
int L_array[12][2] = {{0,1},{1,3},{2,3},{0,2},{4,5},{5,7},{6,7},{4,6},{0,4},{1,5},{3,7},{2,6}};
int D[27][8];
int SEG[27][12];
int POS[9][3] = {{0,1,2},{9,10,11},{18,19,20},{3,4,5},{12,13,14},{21,22,23},{6,7,8},{15,16,17},{24,25,26}};
int four_line[27][6][4];
double min_dist[SIZE];
bool EXIST[27],check[144];
char input_str[9][4];
Point3D start,goal;
Data first_D[27][8];
Data data[64];
Seg first_seg[27][12];
Seg seg[144];
LOC loc[27]; //相対位置計算用
vector<Edge> G[SIZE];
Point3D POINT[SIZE];
vector<Info> info;
vector<int> LINE[144];



double calc_dist(Point3D A,Point3D B){

	double a = A.x-B.x;
	double b = A.y-B.y;
	double c = A.z-B.z;

	return sqrt(a*a+b*b+c*c);
}

void func(){

	for(int i = 0; i < num_POINT; i++){

		G[i].clear();
	}
	for(int i = 0; i < num_seg; i++){

		check[i] = false;
	}

	for(int row = 0; row < 9; row++){
		scanf("%s",input_str[row]);
	}

	//キューブの存在チェック
	for(int row = 0; row < 9; row++){
		for(int col = 0; col < 3; col++){
			if(input_str[row][col] == '#'){

				EXIST[POS[row][col]] = true;

			}else{

				EXIST[POS[row][col]] = false;
			}
		}
	}

	S = -1;
	for(int i = 0; i < num_POINT; i++){

		if(start.X == POINT[i].X && start.Y == POINT[i].Y && start.Z == POINT[i].Z){

			S = i;
			break;
		}
	}
	T = -1;
	for(int i = 0; i < num_POINT; i++){

		if(goal.X == POINT[i].X && goal.Y == POINT[i].Y && goal.Z == POINT[i].Z){

			T = i;
			break;
		}
	}


	//面の有効チェック&エッジ張り
	for(int i = 0; i <= 26; i++){
		if(!EXIST[i])continue;
		for(int k = 0; k < 6; k++){
			if(ADJ[i][k] == -1 || !EXIST[ADJ[i][k]]){
				for(int a = 0; a < 4; a++){
					int from = four_line[i][k][a]; //辺のindex

					//辺自身のエッジ張り
					if(!check[from]){
						check[from] = true;
						for(int b = 1; b < LINE[from].size(); b++){

							double tmp_dist = calc_dist(POINT[LINE[from][b-1]],POINT[LINE[from][b]]);

							G[LINE[from][b-1]].push_back(Edge(LINE[from][b],tmp_dist));
							G[LINE[from][b]].push_back(Edge(LINE[from][b-1],tmp_dist));
						}
					}
					//他の辺とのエッジ張り
					for(int b = a+1; b < 4; b++){
						int to = four_line[i][k][b];
						for(int c = 0; c < LINE[from].size(); c++){
							for(int d = 0; d < LINE[to].size(); d++){

								int A = LINE[from][c];
								int B = LINE[to][d];
								if(A == B)continue;

								double tmp_dist = calc_dist(POINT[A],POINT[B]);

								G[A].push_back(Edge(B,tmp_dist));
								G[B].push_back(Edge(A,tmp_dist));
							}
						}
					}
				}
			}
		}
	}

	for(int i = 0; i < num_POINT; i++){

		min_dist[i] = BIG_NUM;
	}

	priority_queue<State> Q;
	min_dist[S] = 0;

	Q.push(State(S,0));

	int next_node;
	double next_dist;

	while(!Q.empty()){

		if(Q.top().sum_dist > min_dist[Q.top().node_id]+EPS){

			Q.pop();
		}else if(Q.top().node_id == T){

			printf("%.10lf\n",Q.top().sum_dist);
			return;

		}else{

			for(int i = 0; i < G[Q.top().node_id].size(); i++){

				next_node = G[Q.top().node_id][i].to;
				next_dist = Q.top().sum_dist+G[Q.top().node_id][i].dist;

				if(min_dist[next_node] > next_dist+EPS){
					min_dist[next_node] = next_dist;
					Q.push(State(next_node,next_dist));
				}
			}
			Q.pop();
		}
	}
}

bool rangeCheck(int value){

	return value >= 0 && value <= 2;
}

void calc_ADJ(){

	num_loc = 0;

	for(int Y = 0; Y <= 2; Y++){
		for(int Z = 0; Z <= 2; Z++){
			for(int X = 0; X <= 2; X++){

				loc[num_loc].set(X,Y,Z);
				num_loc++;
			}
		}
	}

	for(int i = 0; i <= 26; i++){
		for(int k = 0; k < 6; k++){

			int adj_X = loc[i].X+loc_X[k];
			int adj_Y = loc[i].Y+loc_Y[k];
			int adj_Z = loc[i].Z+loc_Z[k];

			if(adj_X >= 0 && adj_X <= 2 && adj_Y >= 0 &&
					adj_Y <= 2 && adj_Z >= 0 && adj_Z <= 2){

				for(int a = 0; a <= 26; a++){
					if(adj_X == loc[a].X && adj_Y == loc[a].Y && adj_Z == loc[a].Z){
						ADJ[i][k] = a;
						break;
					}
				}

			}else{

				ADJ[i][k] = -1;
			}
		}
	}
}

void calc_PL(){

	//まずは線分の両端の8点列挙
	for(int i = 0; i <= 26; i++){
		for(int k = 0; k <= 7; k++){
			int X = loc[i].X+D_X[k];
			int Y = loc[i].Y+D_Y[k];
			int Z = loc[i].Z+D_Z[k];

			first_D[i][k].set(X,Y,Z);
		}
	}

	//indexに変換する
	num_data = 0;
	for(int i = 0; i <= 26; i++){
		for(int k = 0; k <= 7; k++){

			int X = first_D[i][k].X;
			int Y = first_D[i][k].Y;
			int Z = first_D[i][k].Z;

			bool FLG = false;
			for(int a = 0; a < num_data; a++){
				if(X == data[a].X && Y == data[a].Y && Z == data[a].Z){
					D[i][k] = a;
					FLG = true;
					break;
				}
			}

			if(!FLG){
				D[i][k] = num_data;
				data[num_data].set(X,Y,Z);
				num_data++;
			}
		}
	}

	for(int i = 0; i < num_data; i++){

		data[i].copy();
	}

	num_POINT = 0;
	for(int i = 0; i < num_data; i++){
		POINT[i].X = data[i].X;
		POINT[i].Y = data[i].Y;
		POINT[i].Z = data[i].Z;
		POINT[i].copy();
		num_POINT++;
	}

	//6面の4辺を列挙する
	num_seg = 0;
	int tmp_index;

	for(int i = 0; i <= 26; i++){
		for(int k = 0; k < 6; k++){ //面
			for(int p = 0; p < 4; p++){
				int from = D[i][L_array[have_L[k][p]][0]];
				int to = D[i][L_array[have_L[k][p]][1]];

				if(from > to){

					swap(from,to);
				}
				tmp_index = -1;
				for(int a = 0; a < num_seg; a++){
					if(seg[a].A == from && seg[a].B == to){

						tmp_index = a;
						break;
					}
				}
				if(tmp_index == -1){

					tmp_index = num_seg;
					seg[num_seg].A = from;
					seg[num_seg].B = to;
					num_seg++;
				}
				four_line[i][k][p] = tmp_index;
			}
		}
	}

	//辺上の点を計算
	for(int i = 0; i < num_seg; i++){
		info.clear();
		info.push_back(Info(POINT[seg[i].A],seg[i].A));
		info.push_back(Info(POINT[seg[i].B],seg[i].B));
		sort(info.begin(),info.end());
		Point3D p_L = info[0].p,p_R = info[1].p;
		for(int ALL = 2; ALL <= 9; ALL++){
			for(int left = 1; left <= ALL-1; left++){
				int right = ALL-left;
				Point3D tmp_p = (p_R*(double)(left)+p_L*(double)(right))/(double)ALL;

				int tmp_id = -1;
				for(int a = 0; a < num_POINT; a++){

					if(POINT[a] == tmp_p){

						tmp_id = a;
						break;
					}
				}
				if(tmp_id == -1){
					tmp_id = num_POINT;
					POINT[num_POINT] = tmp_p;
					POINT[num_POINT].X = -1;
					num_POINT++;
				}
				info.push_back(Info(tmp_p,tmp_id));
			}
		}
		sort(info.begin(),info.end());
		info.erase(unique(info.begin(),info.end()),info.end());

		for(int a = 0; a < info.size(); a++){

			LINE[i].push_back(info[a].index);
		}
	}
}


int main(){

	calc_ADJ();
	calc_PL();

	while(true){

		scanf("%d %d %d %d %d %d",&start.X,&start.Y,&start.Z,&goal.X,&goal.Y,&goal.Z);
		if(start.X == 0 && start.Y == 0 && start.Z == 0 && goal.X == 0 && goal.Y == 0 && goal.Z == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 2130
memory_kb: 25656
final_rank: 2

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 10005

enum DIR{
	UP,
	East,
	North,
	West,
	South,
	Down,
};


struct LOC{
	void set(int arg_X,int arg_Y,int arg_Z){
		X = arg_X;
		Y = arg_Y;
		Z = arg_Z;
	}
	void debug(){

		printf("X:%d Y:%d Z:%d\n",X,Y,Z);
	}
	int X,Y,Z;
};


struct Point3D{
	Point3D(double arg_x,double arg_y,double arg_z){
		x = arg_x;
		y = arg_y;
		z = arg_z;
		X = Y = Z = 0;
	}

	Point3D(){
		x = y = z = 0.0;
		X = Y = Z = 0;
	}

	Point3D operator + (Point3D p){ return Point3D(x+p.x,y+p.y,z+p.z); }
	Point3D operator - (Point3D p){ return Point3D(x-p.x,y-p.y,z-p.z);}
	Point3D operator * (double a){ return Point3D(a*x,a*y,a*z); }
	Point3D operator / (double a){ return Point3D(x/a,y/a,z/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y + z*z; }

	bool operator<(const Point3D &p) const{
		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else if(fabs(y-p.y) > EPS){

			return y < p.y;
		}else{

			return z < p.z;
		}
	}

	void set(int arg_X,int arg_Y,int arg_Z){
		X = arg_X;
		Y = arg_Y;
		Z = arg_Z;
	}

	void copy(){
		x = X;
		y = Y;
		z = Z;
	}

	bool operator == (const Point3D &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS && fabs(z-p.z) < EPS;
	}
	void debug(){

		printf("(%.3lf,%.3lf,%.3lf)\n",x,y,z);
	}
	int X,Y,Z;
	double x,y,z;
};

typedef Point3D Vector3D;

struct Line{
	Line(){

	}
	Line(Point3D a,Point3D b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point3D p[2];
};

struct Data{
	Data(){

		X = Y = Z = 0;
		x = y = z = 0;
	}
	Data(double arg_x,double arg_y,double arg_z){
		x = arg_x;
		y = arg_y;
		z = arg_z;
		X = Y = Z = 0;
	}

	void set(int arg_X,int arg_Y,int arg_Z){
		X = arg_X;
		Y = arg_Y;
		Z = arg_Z;
	}
	void copy(){
		x = X;
		y = Y;
		z = Z;
	}
	void debug(){

		printf("%d %d %d\n",X,Y,Z);
	}
	int X,Y,Z;
	double x,y,z;
};

struct Seg{
	void set(int arg_A,int arg_B){
		A = arg_A;
		B = arg_B;
	}
	int A,B;
};

struct Edge{
	Edge(int arg_to,double arg_dist){
		to = arg_to;
		dist = arg_dist;
	}
	int to;
	double dist;
};

struct Info{
	Info(){
		index = 0;
	}
	Info(Point3D arg_p,int arg_index){
		p = arg_p;
		index = arg_index;
	}
	bool operator<(const struct Info &arg)const{

		return p < arg.p;
	}
	bool operator==(const struct Info &arg) const{

		return p == arg.p;
	}
	Point3D p;
	int index;
};

struct State{
	State(int arg_node_id,double arg_sum_dist){
		node_id = arg_node_id;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct State  &arg) const{

		return sum_dist > arg.sum_dist; //総距離の昇順(PQ)
	}
	int node_id;
	double sum_dist;
};

int num_loc,num_data,num_POINT,num_seg;
int S,T;
int ADJ[27][6];
int loc_X[6] = {0,1,0,-1,0,0},loc_Y[6] = {-1,0,0,0,0,1},loc_Z[6] = {0,0,1,0,-1,0};
int D_X[8] = {0,1,0,1,0,1,0,1},D_Y[8] = {0,0,0,0,1,1,1,1},D_Z[8] = {0,0,1,1,0,0,1,1};
int have_L[6][4] ={{0,1,2,3},{1,5,9,10},{2,6,10,11},{3,7,8,11},{0,4,8,9},{4,5,6,7}};
int L_array[12][2] = {{0,1},{1,3},{2,3},{0,2},{4,5},{5,7},{6,7},{4,6},{0,4},{1,5},{3,7},{2,6}};
int D[27][8];
int SEG[27][12];
int REV[3][3][3];
int POS[9][3] = {{0,1,2},{9,10,11},{18,19,20},{3,4,5},{12,13,14},{21,22,23},{6,7,8},{15,16,17},{24,25,26}};
int four_line[27][6][4];
double min_dist[SIZE];
bool EXIST[27],check[144];
char input_str[9][4];
Point3D start,goal;
Data first_D[27][8];
Data data[64];
Seg first_seg[27][12];
Seg seg[144];
LOC loc[27]; //相対位置計算用
vector<Edge> G[SIZE];
Point3D POINT[SIZE];
vector<Info> info;
vector<int> LINE[144];






int gcd(int x,int y){

	x = abs(x);
	y = abs(y);

	if(x < y){
		swap(x,y);
	}
	if(y == 0){
		return x;
	}else{
		return gcd(y,x%y);
	}
}

double calc_dist(Point3D A,Point3D B){

	double a = A.x-B.x;
	double b = A.y-B.y;
	double c = A.z-B.z;

	return sqrt(a*a+b*b+c*c);
}

void func(){

	for(int i = 0; i < num_POINT; i++){

		G[i].clear();
	}
	for(int i = 0; i < num_seg; i++){

		check[i] = false;
	}



	for(int row = 0; row < 9; row++){
		scanf("%s",input_str[row]);
	}

	//キューブの存在チェック
	for(int row = 0; row < 9; row++){
		for(int col = 0; col < 3; col++){
			if(input_str[row][col] == '#'){

				EXIST[POS[row][col]] = true;

			}else{

				EXIST[POS[row][col]] = false;
			}
		}
	}

	S = -1;
	for(int i = 0; i < num_POINT; i++){

		if(start.X == POINT[i].X && start.Y == POINT[i].Y && start.Z == POINT[i].Z){

			S = i;
			break;
		}
	}
	T = -1;
	for(int i = 0; i < num_POINT; i++){

		if(goal.X == POINT[i].X && goal.Y == POINT[i].Y && goal.Z == POINT[i].Z){

			T = i;
			break;
		}
	}


	//面の有効チェック&エッジ張り
	for(int i = 0; i <= 26; i++){
		if(!EXIST[i])continue;
		for(int k = 0; k < 6; k++){
			if(ADJ[i][k] == -1 || !EXIST[ADJ[i][k]]){
				for(int a = 0; a < 4; a++){
					int from = four_line[i][k][a]; //辺のindex

					//辺自身のエッジ張り
					if(!check[from]){
						check[from] = true;
						for(int b = 1; b < LINE[from].size(); b++){

							double tmp_dist = calc_dist(POINT[LINE[from][b-1]],POINT[LINE[from][b]]);

							G[LINE[from][b-1]].push_back(Edge(LINE[from][b],tmp_dist));
							G[LINE[from][b]].push_back(Edge(LINE[from][b-1],tmp_dist));
						}
					}
					//他の辺とのエッジ張り
					for(int b = a+1; b < 4; b++){
						int to = four_line[i][k][b];
						for(int c = 0; c < LINE[from].size(); c++){
							for(int d = 0; d < LINE[to].size(); d++){

								int A = LINE[from][c];
								int B = LINE[to][d];
								if(A == B)continue;

								double tmp_dist = calc_dist(POINT[A],POINT[B]);

								G[A].push_back(Edge(B,tmp_dist));
								G[B].push_back(Edge(A,tmp_dist));
							}
						}
					}
				}
			}
		}
	}

/*
	printf("S:%d T:%d\n",S,T);
	return;*/

	for(int i = 0; i < num_POINT; i++){

		min_dist[i] = BIG_NUM;
	}

	priority_queue<State> Q;
	min_dist[S] = 0;

	Q.push(State(S,0));

	int next_node;
	double next_dist;

	while(!Q.empty()){

		if(Q.top().sum_dist > min_dist[Q.top().node_id]+EPS){

			Q.pop();
		}else if(Q.top().node_id == T){

			printf("%.10lf\n",Q.top().sum_dist);
			return;

		}else{

			for(int i = 0; i < G[Q.top().node_id].size(); i++){

				next_node = G[Q.top().node_id][i].to;
				next_dist = Q.top().sum_dist+G[Q.top().node_id][i].dist;

				if(min_dist[next_node] > next_dist+EPS){
					min_dist[next_node] = next_dist;
					Q.push(State(next_node,next_dist));
				}
			}
			Q.pop();
		}
	}
	printf("-1\n");
}

bool rangeCheck(int value){

	return value >= 0 && value <= 2;
}

//tmp_pを含むcubeのインデックスを取得
int get_index(Point3D tmp_p){

	int X = (int)(floor(tmp_p.x));
	int Y = (int)(floor(tmp_p.y));
	int Z = (int)(floor(tmp_p.z));

	//printf("tmp_p.z:%.3lf Z:%d\n",tmp_p.z,Z);

	if(rangeCheck(X)&&rangeCheck(Y)&&rangeCheck(Z)){

		return REV[X][Y][Z];

	}else{

		return -1;
	}
}



void calc_ADJ(){

	num_loc = 0;

	for(int Y = 0; Y <= 2; Y++){
		for(int Z = 0; Z <= 2; Z++){
			for(int X = 0; X <= 2; X++){

				loc[num_loc].set(X,Y,Z);
				REV[X][Y][Z] = num_loc; //★★左上手前の点の逆引き表★★
				num_loc++;
			}
		}
	}

	for(int i = 0; i <= 26; i++){
		for(int k = 0; k < 6; k++){

			int adj_X = loc[i].X+loc_X[k];
			int adj_Y = loc[i].Y+loc_Y[k];
			int adj_Z = loc[i].Z+loc_Z[k];

			if(adj_X >= 0 && adj_X <= 2 && adj_Y >= 0 &&
					adj_Y <= 2 && adj_Z >= 0 && adj_Z <= 2){

				for(int a = 0; a <= 26; a++){
					if(adj_X == loc[a].X && adj_Y == loc[a].Y && adj_Z == loc[a].Z){
						ADJ[i][k] = a;
						break;
					}
				}

			}else{

				ADJ[i][k] = -1;
			}
		}
	}
}

void calc_PL(){

	//まずは線分の両端の8点列挙
	for(int i = 0; i <= 26; i++){
		for(int k = 0; k <= 7; k++){
			int X = loc[i].X+D_X[k];
			int Y = loc[i].Y+D_Y[k];
			int Z = loc[i].Z+D_Z[k];

			first_D[i][k].set(X,Y,Z);
		}
	}

	//indexに変換する
	num_data = 0;
	for(int i = 0; i <= 26; i++){
		for(int k = 0; k <= 7; k++){

			int X = first_D[i][k].X;
			int Y = first_D[i][k].Y;
			int Z = first_D[i][k].Z;

			bool FLG = false;
			for(int a = 0; a < num_data; a++){
				if(X == data[a].X && Y == data[a].Y && Z == data[a].Z){
					D[i][k] = a;
					FLG = true;
					break;
				}
			}

			if(!FLG){
				D[i][k] = num_data;
				data[num_data].set(X,Y,Z);
				num_data++;
			}
		}
	}

	for(int i = 0; i < num_data; i++){

		data[i].copy();
	}

	num_POINT = 0;
	for(int i = 0; i < num_data; i++){
		POINT[i].X = data[i].X;
		POINT[i].Y = data[i].Y;
		POINT[i].Z = data[i].Z;
		POINT[i].copy();
		num_POINT++;
	}

	//6面の4辺を列挙する
	num_seg = 0;
	int tmp_index;

	for(int i = 0; i <= 26; i++){
		for(int k = 0; k < 6; k++){ //面
			for(int p = 0; p < 4; p++){
				int from = D[i][L_array[have_L[k][p]][0]];
				int to = D[i][L_array[have_L[k][p]][1]];

				if(from > to){

					swap(from,to);
				}
				tmp_index = -1;
				for(int a = 0; a < num_seg; a++){
					if(seg[a].A == from && seg[a].B == to){

						tmp_index = a;
						break;
					}
				}
				if(tmp_index == -1){

					tmp_index = num_seg;
					seg[num_seg].A = from;
					seg[num_seg].B = to;
					num_seg++;
				}
				four_line[i][k][p] = tmp_index;
			}
		}
	}

	//辺上の点を計算
	for(int i = 0; i < num_seg; i++){
		info.clear();
		info.push_back(Info(POINT[seg[i].A],seg[i].A));
		info.push_back(Info(POINT[seg[i].B],seg[i].B));
		sort(info.begin(),info.end());
		Point3D p_L = info[0].p,p_R = info[1].p;
		for(int ALL = 2; ALL <= 9; ALL++){
			for(int left = 1; left <= ALL-1; left++){
				int right = ALL-left;
				Point3D tmp_p = (p_R*(double)(left)+p_L*(double)(right))/(double)ALL;

				int tmp_id = -1;
				for(int a = 0; a < num_POINT; a++){

					if(POINT[a] == tmp_p){

						tmp_id = a;
						break;
					}
				}
				if(tmp_id == -1){
					tmp_id = num_POINT;
					POINT[num_POINT] = tmp_p;
					POINT[num_POINT].X = -1;
					num_POINT++;
				}
				info.push_back(Info(tmp_p,tmp_id));
			}
		}
		sort(info.begin(),info.end());
		info.erase(unique(info.begin(),info.end()),info.end());

		for(int a = 0; a < info.size(); a++){

			LINE[i].push_back(info[a].index);
		}
	}
}


int main(){

	calc_ADJ();
	calc_PL();

	while(true){

		scanf("%d %d %d %d %d %d",&start.X,&start.Y,&start.Z,&goal.X,&goal.Y,&goal.Z);
		if(start.X == 0 && start.Y == 0 && start.Z == 0 && goal.X == 0 && goal.Y == 0 && goal.Z == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 2160
memory_kb: 25572
final_rank: 3

code_snippet: #include<stdio.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<math.h>
using namespace std;
char in[3][3][4];
int DIV=7;
int gcd(int a,int b){
	while(a){
		b%=a;int c=a;a=b;b=c;
	}return b;
}
const double EPS = 1e-10;
const double INF = 1e+10;
const double PI = acos(-1);
int sig(double r) { return (r < -EPS) ? -1 : (r > +EPS) ? +1 : 0; }
inline double ABS(double a){return max(a,-a);}
struct Pt {
	double x, y,z;
	Pt() {}
	Pt(double x, double y,double z) : x(x), y(y),z(z) {}
	Pt operator+(const Pt &a) const { return Pt(x + a.x, y + a.y,z+a.z); }
	Pt operator-(const Pt &a) const { return Pt(x - a.x, y - a.y,z-a.z); }
//	Pt operator*(const Pt &a) const { return Pt(x * a.x - y * a.y, x * a.y + y * a.x); }
	Pt operator-() const { return Pt(-x, -y,-z); }
	Pt operator*(const double &k) const { return Pt(x * k, y * k,z*k); }
	Pt operator/(const double &k) const { return Pt(x / k, y / k,z/k); }
	double ABS() const { return sqrt(x * x + y * y+z*z); }
	double abs2() const { return x * x + y * y+z*z; }
//	double arg() const { return atan2(y, x); }
	double dot(const Pt &a) const { return x * a.x + y * a.y+z*a.z; }
//	double det(const Pt &a) const { return x * a.y - y * a.x; }
};
double ijk[110000];
int v[110000];
int can[4][4][4];
int canx[4][4][4];
int cany[4][4][4];
int canz[4][4][4];
int canxy[4][4][4];
int canyz[4][4][4];
int canzx[4][4][4];
int rev[110000];
char ss[4];
int main(){
	int a,b,c,d,e,f;
	while(scanf("%d%d%d%d%d%d",&a,&b,&c,&d,&e,&f),a+b+c+d+e+f){
		for(int i=0;i<3;i++)for(int j=0;j<3;j++){
			scanf("%s",ss);
			for(int k=0;k<3;k++)in[k][j][i]=ss[k];
		}
		vector<Pt> hb;
		for(int i=0;i<4;i++)for(int j=0;j<4;j++)for(int k=0;k<4;k++){
			can[i][j][k]=canx[i][j][k]=cany[i][j][k]=canz[i][j][k]=0;
			canxy[i][j][k]=canyz[i][j][k]=canzx[i][j][k]=0;
		}
		for(int i=0;i<4;i++)for(int j=0;j<4;j++)for(int k=0;k<4;k++){
			if(i==0||i==3||j==0||j==3||k==0||k==3)can[i][j][k]=2;
			if(j==0||j==3||k==0||k==3)canx[i][j][k]=2;
			if(i==0||i==3||k==0||k==3)cany[i][j][k]=2;
			if(i==0||i==3||j==0||j==3)canz[i][j][k]=2;
			if(k==0||k==3)canxy[i][j][k]=2;
			if(i==0||i==3)canyz[i][j][k]=2;
			if(j==0||j==3)canzx[i][j][k]=2;
		}
		for(int i=0;i<3;i++)for(int j=0;j<3;j++)for(int k=0;k<3;k++){
			int key=0;
			if(in[i][j][k]=='#'){
				key=1;
			}else{
				key=2;
			}
			for(int l=0;l<8;l++){
				can[i+l/4][j+l%4/2][k+l%2]|=key;
			}
			for(int l=0;l<4;l++){
				canx[i][j+l/2][k+l%2]|=key;
				cany[i+l/2][j][k+l%2]|=key;
				canz[i+l/2][j+l%2][k]|=key;
			}
			for(int l=0;l<2;l++){
				canxy[i][j][k+l%2]|=key;
				canyz[i+l%2][j][k]|=key;
				canzx[i][j+l%2][k]|=key;
			}
		}
		/*for(int i=0;i<4;i++){
			for(int j=0;j<4;j++){
				for(int k=0;k<4;k++)printf("%d ",can[k][j][i]);
				printf("\n");
			}
			printf("\n");
		}*/
		for(int i=0;i<=3;i++){
			for(int j=0;j<=3;j++){
				for(int k=0;k<=3;k++){
					if(can[i][j][k]==3)hb.push_back(Pt((double)i,(double)j,(double)k));
				}
				for(int k=0;k<3;k++){
					for(int l=2;l<=DIV;l++){
						for(int m=1;m<l;m++){
							if(gcd(m,l)!=1)continue;
							if(canz[i][j][k]==3)hb.push_back(Pt((double)i,(double)j,k+(double)m/l));
							if(cany[i][k][j]==3)hb.push_back(Pt((double)i,k+(double)m/l,(double)j));
							if(canx[k][i][j]==3)hb.push_back(Pt(k+(double)m/l,(double)i,(double)j));
						}
					}
				}
			}
		}
		int sz=hb.size();
		for(int i=0;i<sz;i++){
			v[i]=0;
			ijk[i]=99999999;
		}
		Pt start=Pt(a,b,c);
		Pt goal=Pt(d,e,f);
		for(int i=0;i<sz;i++){
			if((hb[i]-start).ABS()<EPS){
				ijk[i]=0;
			}
		}
		for(int i=0;i<sz;i++){
			int at=0;
			double dist=999999999;
			for(int j=0;j<sz;j++){
				if(!v[j]&&dist>ijk[j]){
					dist=ijk[j];at=j;
				}
			}
			v[at]=1;
		//	printf("%f %f %f: %f\n",hb[at].x,hb[at].y,hb[at].z,ijk[at]);
			if((hb[at]-goal).ABS()<EPS){
				printf("%.12f\n",dist);
				int cur=at;
				//while((hb[cur]-start).ABS()>EPS){
				//	cur=rev[cur];
				//	printf("%f %f %f: %f\n",hb[cur].x,hb[cur].y,hb[cur].z,ijk[cur]);
				//}
				break;
			}
			for(int j=0;j<sz;j++){
				if(v[j])continue;
				bool X=false;
				bool Y=false;
				bool Z=false;
				int xx=(int)(min(hb[j].x,hb[at].x)+EPS);
				int yy=(int)(min(hb[j].y,hb[at].y)+EPS);
				int zz=(int)(min(hb[j].z,hb[at].z)+EPS);
				if(ABS(hb[j].x-hb[at].x)<EPS&&ABS(hb[j].x-xx)<EPS)X=true;
				if(ABS(hb[j].y-hb[at].y)<EPS&&ABS(hb[j].y-yy)<EPS)Y=true;
				if(ABS(hb[j].z-hb[at].z)<EPS&&ABS(hb[j].z-zz)<EPS)Z=true;
				if(!X&&!Y&&!Z)continue;
				if(!X&&(int)(min(hb[j].x+1,hb[at].x+1)+EPS)!=(int)(max(hb[at].x+1,hb[j].x+1)-EPS))continue;
				if(!Y&&(int)(min(hb[j].y+1,hb[at].y+1)+EPS)!=(int)(max(hb[at].y+1,hb[j].y+1)-EPS))continue;
				if(!Z&&(int)(min(hb[j].z+1,hb[at].z+1)+EPS)!=(int)(max(hb[at].z+1,hb[j].z+1)-EPS))continue;
				bool can=false;
				bool Xs=false;
				bool Ys=false;
				bool Zs=false;
				if(ABS(hb[j].x-(int)(hb[j].x+EPS))<EPS)Xs=true;
				if(ABS(hb[j].y-(int)(hb[j].y+EPS))<EPS)Ys=true;
				if(ABS(hb[j].z-(int)(hb[j].z+EPS))<EPS)Zs=true;
				if(X&&canyz[xx][yy][zz]==3)can=true;
				if(Y&&canzx[xx][yy][zz]==3)can=true;
				if(Z&&canxy[xx][yy][zz]==3)can=true;
				if(X&&Y&&Xs&&Ys&&canz[xx][yy][zz]==3)can=true;
				if(Z&&Y&&Zs&&Ys&&canx[xx][yy][zz]==3)can=true;
				if(X&&Z&&Xs&&Zs&&cany[xx][yy][zz]==3)can=true;
				if(can){
					double tmp=(hb[j]-hb[at]).ABS();
					if(ijk[j]>tmp+ijk[at]){
						ijk[j]=tmp+ijk[at];
						rev[j]=at;
					}
				}
			}
		}
	}
}
accuracy: 1
time_ms: 5610
memory_kb: 1252
final_rank: 1

code_snippet: #include <stdio.h>
#include <math.h>
#include <vector>
#include <queue>
#include <utility>
#include <algorithm>
using namespace std;

struct point{
  int x, y, z;
  point(int x_, int y_, int z_) : x(x_), y(y_), z(z_) {}
  bool operator< (const point& rhs) const {
    return false;
  }
};

const int dv = 18;
const int sd = 420;

int b[5][5][5];
int dvs[dv + 1] = {0, 60, 70, 84, 105, 120, 140, 168, 180, 210, 240, 252, 280, 300, 315, 336, 350, 360};
int rot[dv * 4 + 1][2];

int xtov[dv * 3 + 1];

vector<point> ed[dv * 3 + 1][dv * 3 + 1][dv * 3 + 1];
priority_queue< pair<double, point> > pq;
bool vis[dv * 3 + 1][dv * 3 + 1][dv * 3 + 1];

double dist(int xa, int ya, int za, int xb, int yb, int zb){
  int dx = xa - xb, dy = ya - yb, dz = za - zb;
  double d = sqrt(dx * dx + dy * dy + dz * dz);
  return d;
}

int main(){
  int i, j, k;
  for(i = 0; i <= dv * 3 + 1; i++){
    if(i < dv) xtov[i] = dvs[i];
    else xtov[i] = xtov[i - dv] + sd;
  }
  for(i = 0; i < dv; i++){
    rot[i][0] = i;
    rot[i][1] = 0;
    rot[dv + i][0] = dv;
    rot[dv + i][1] = i;
    rot[2 * dv + i][0] = dv - i;
    rot[2 * dv + i][1] = dv;
    rot[3 * dv + i][0] = 0;
    rot[3 * dv + i][1] = dv - i;
  }

  for(;;){
    int x1, y1, z1;
    int x2, y2, z2;
    scanf("%d%d%d", &x1, &y1, &z1);
    scanf("%d%d%d", &x2, &y2, &z2);
    if(x1 == 0 && y1 == 0 && z1 == 0
        && x2 == 0 && y2 == 0 && z2 == 0) break;

    for(i = 0; i <= 3 * dv; i++){
      for(j = 0; j <= 3 * dv; j++){
        for(k = 0; k <= 3 * dv; k++){
          ed[i][j][k].clear();
          vis[i][j][k] = false;
        }
      }
    }
    while(!pq.empty()) pq.pop();

    char tmp[5];
    for(i = 0; i < 3; i++){
      for(j = 0; j < 3; j++){
        scanf("%s", tmp);
        for(k = 0; k < 3; k++){
          b[k][j][i] = (tmp[k] == '#');
        }
      }
    }

    for(i = 0; i <= 3; i++){
      for(j = 0; j <= 3; j++){
        for(k = 0; k <= 3; k++){
          // (i, j, k) (i + 1, j, k) (i, j + 1, k) (i + 1, j + 1, k)
          // square (i, j, k - 1), (i, j, k)
          if(i < 3 && j < 3 && (k == 0 ? 0 : b[i][j][k - 1]) + b[i][j][k] == 1){
            for(int l0 = 0; l0 < 4 * dv; l0++){
              for(int l1 = l0 + 1; l1 < 4 * dv; l1++){
                // (i * dv + rot[l][0], j * dv + rot[l][1], k * dv)
                int nx0 = i * dv + rot[l0][0], ny0 = j * dv + rot[l0][1], nz0 = k * dv;
                int nx1 = i * dv + rot[l1][0], ny1 = j * dv + rot[l1][1], nz1 = k * dv;
                ed[nx0][ny0][nz0].push_back(point(nx1, ny1, nz1));
                ed[nx1][ny1][nz1].push_back(point(nx0, ny0, nz0));
              }
            }
          }
          // (i, j, k) (i + 1, j, k) (i, j, k + 1) (i + 1, j, k + 1)
          // square (i, j - 1, k), (i, j, k)
          if(i < 3 && k < 3 && (j == 0 ? 0 : b[i][j - 1][k]) + b[i][j][k] == 1){
            for(int l0 = 0; l0 < 4 * dv; l0++){
              for(int l1 = l0 + 1; l1 < 4 * dv; l1++){
                // (i * dv + rot[l][0], j * dv, k * dv + rot[l][1])
                int nx0 = i * dv + rot[l0][0], ny0 = j * dv, nz0 = k * dv + rot[l0][1];
                int nx1 = i * dv + rot[l1][0], ny1 = j * dv, nz1 = k * dv + rot[l1][1];
                ed[nx0][ny0][nz0].push_back(point(nx1, ny1, nz1));
                ed[nx1][ny1][nz1].push_back(point(nx0, ny0, nz0));
              }
            }
          }
          // (i, j, k) (i, j + 1, k) (i, j, k + 1) (i, j + 1, k + 1)
          // square (i - 1, j, k), (i, j, k)
          if(j < 3 && k < 3 && (i == 0 ? 0 : b[i - 1][j][k]) + b[i][j][k] == 1){
            for(int l0 = 0; l0 < 4 * dv; l0++){
              for(int l1 = l0 + 1; l1 < 4 * dv; l1++){
                // (i * dv, j * dv + rot[l][0], k * dv + rot[l][1])
                int nx0 = i * dv, ny0 = j * dv + rot[l0][0], nz0 = k * dv + rot[l0][1];
                int nx1 = i * dv, ny1 = j * dv + rot[l1][0], nz1 = k * dv + rot[l1][1];
                ed[nx0][ny0][nz0].push_back(point(nx1, ny1, nz1));
                ed[nx1][ny1][nz1].push_back(point(nx0, ny0, nz0));
              }
            }
          }
        }
      }
    }

    pq.push(make_pair(0.0, point(x1 * dv, y1 * dv, z1 * dv)));
    double ans = 0.0;

    while(!pq.empty()){
      double nd = pq.top().first;
      int nx = pq.top().second.x, ny = pq.top().second.y, nz = pq.top().second.z;
      pq.pop();

      if(vis[nx][ny][nz]) continue;
      vis[nx][ny][nz] = true;

      if(nx == x2 * dv && ny == y2 * dv && nz == z2 * dv){
        ans = nd;
        break;
      }

      for(point pp : ed[nx][ny][nz]){
        if(!vis[pp.x][pp.y][pp.z]){
          pq.push(make_pair(nd - dist(xtov[nx], xtov[ny], xtov[nz], xtov[pp.x], xtov[pp.y], xtov[pp.z]), pp));
        }
      }
    }
    printf("%.20lf\n", -ans / sd);
  }
  return 0;
}
accuracy: 1
time_ms: 4280
memory_kb: 16128
final_rank: 4

code_snippet: #include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<cassert>
#include<utility>
#include<algorithm>

using namespace std;

typedef double Real;
typedef pair<int,int> P;

const Real eps=1e-7;
const Real inf=1e9;

template<class T> bool eq(T a,T b){
	return abs(a-b)<eps;
}
template<class T> int sgn(T a){
	if(eq(a,0.0)) return 0;
	if(a>0) return 1;
	return -1;
}

//vector<Real> vals;
Real vals[140];
int vals_id=0;
//vector<int> valid_vnum;
int valid_vnum[7000];
int valid_vnum_id=0;

int rev_valid_vnum[140*140*140];

int encode(Real x,Real y,Real z){
//	int xid = distance(vals.begin(),lower_bound(vals.begin(),vals.end(),x-eps));
//	int yid = distance(vals.begin(),lower_bound(vals.begin(),vals.end(),y-eps));
//	int zid = distance(vals.begin(),lower_bound(vals.begin(),vals.end(),z-eps));
	int xid=lower_bound(vals,vals+vals_id,x-eps)-vals;
	int yid=lower_bound(vals,vals+vals_id,y-eps)-vals;
	int zid=lower_bound(vals,vals+vals_id,z-eps)-vals;
//	int v=xid + vals.size()*yid + vals.size()*vals.size()*zid;
	int v=xid + vals_id*yid + vals_id*vals_id*zid;
//	int res = distance(valid_vnum.begin(),lower_bound(valid_vnum.begin(),valid_vnum.end(),v));
//	int res = lower_bound(valid_vnum,valid_vnum+valid_vnum_id,v)-valid_vnum;
	int res = rev_valid_vnum[v];
	return res;
}

const int V = 10000;// 140*140*140;

int head[V],to[500500],nxt[500500],m;
Real cost[500500];
void init_edge(){
	for(int i=0;i<V;i++) head[i]=-1;
	m=0;
}
void add_edge(int u,int v,Real c){
	nxt[m]=head[u];to[m]=v;cost[m]=c;head[u]=m;m++;
	nxt[m]=head[v];to[m]=u;cost[m]=c;head[v]=m;m++;
	if(m>500000) assert(0);
}

//vector<Real> as,bs,cs,ds;
Real as[2200],bs[2200],cs[2200],ds[2200];
int aid=0;
typedef pair<Real,Real> PR;
int gcd(int x,int y){
	if(x<y) return gcd(y,x);
	if(y==0) return x;
	return gcd(y,x%y);
}

PR tmp[30];

void genEdges(){
	for(int i=1;i<=12;i++) for(int j=1;j<=12;j++){
		if(gcd(i,j)!=1) continue;
	//	vector<PR> tmp;
		int tmp_id=0;
		for(int k=1;k<i;k++){
			Real y=(Real)k*j/i;
		//	tmp.push_back(PR(k,y));
			tmp[tmp_id++]=PR(k,y);
		}
		for(int k=1;k<j;k++){
			Real x=(Real)i*k/j;
		//	tmp.push_back(PR(x,k));
			tmp[tmp_id++]=PR(x,k);
		}
		//tmp.push_back(PR(0,0));
		//tmp.push_back(PR(i,j));
		tmp[tmp_id++]=PR(0,0);
		tmp[tmp_id++]=PR(i,j);
//		sort(tmp.begin(),tmp.end());
		sort(tmp,tmp+tmp_id);
/*		if(i == 3 && j == 4){
			for(int k = 0; k < tmp.size(); k++){
				printf("%f %f\n",tmp[k].first,tmp[k].second);
			}
//			exit(0);
		}*/
	//	for(int k=0;k+1<tmp.size();k++){
		for(int k=0;k+1<tmp_id;k++){
			Real a_=tmp[k].first;
			Real a=a_-(int)(a_+eps);
			Real b_=tmp[k].second;
			Real b=b_-(int)(b_+eps);
			Real c_=tmp[k+1].first;
			Real c=c_-(int)(c_-eps);
			Real d_=tmp[k+1].second;
			Real d=d_-(int)(d_-eps);
		/*	as.push_back(a);
			bs.push_back(b);
			cs.push_back(c);
			ds.push_back(d);
			as.push_back(1-a);
			bs.push_back(b);
			cs.push_back(1-c);
			ds.push_back(d);*/
			as[aid]=a;
			bs[aid]=b;
			cs[aid]=c;
			ds[aid]=d;
			aid++;
			as[aid]=1-a;
			bs[aid]=b;
			cs[aid]=1-c;
			ds[aid]=d;
			aid++;
//			if(i == 3 && j == 4){
//				printf("%f %f %f %f\n", a,b,c,d);
//			}
		}
	}
/*	for(int i=0;i<as.size();i++){
		printf("%.2f %.2f %.2f %.2f\n",as[i],bs[i],cs[i],ds[i]);
	}
	exit(0);*/
}
Real getDis(Real a,Real b,Real c,Real p,Real q,Real r){
	Real d1=a-p,d2=b-q,d3=c-r;
	return sqrt(d1*d1+d2*d2+d3*d3);
}

bool exi[5][5][5];
void genGraph(){
//	int cntOut=0;
/*	for(int i=0;i<140*140*140;i++){
		G[i].clear();
	}*/
	init_edge();
	for(int x=1;x<=4;x++){
		for(int y=1;y<=3;y++) for(int z=1;z<=3;z++){
			int cnt=0;
			if(exi[x-1][y][z]) cnt++;
			if(exi[x][y][z]) cnt++;
			if(cnt!=1) continue;
		//	for(int i=0;i<as.size();i++){
			for(int i=0;i<aid;i++){
				Real x1=x,y1_=y+as[i],z1=z+bs[i];
				Real x2=x,y2_=y+cs[i],z2=z+ds[i];
				int u=encode(x1,y1_,z1);
				int v=encode(x2,y2_,z2);
				Real d=getDis(x1,y1_,z1,x2,y2_,z2);
				add_edge(u,v,d);
		//		G[u].push_back(edge(v,d));
		//		G[v].push_back(edge(u,d));
		//		if(++cntOut<=20){
					//printf("%d %d\n",u,v);
//					printf("%.2f %.2f %.2f %.2f %.2f %.2f\n",
//					x1,y1_,z1,x2,y2_,z2);
		//		}
			}
		}
	}
	for(int y=1;y<=4;y++){
		for(int x=1;x<=3;x++) for(int z=1;z<=3;z++){
			int cnt=0;
			if(exi[x][y-1][z]) cnt++;
			if(exi[x][y][z]) cnt++;
			if(cnt!=1) continue;
		//	for(int i=0;i<as.size();i++){
			for(int i=0;i<aid;i++){
				Real x1=x+as[i],y1_=y,z1=z+bs[i];
				Real x2=x+cs[i],y2_=y,z2=z+ds[i];
				int u=encode(x1,y1_,z1);
				int v=encode(x2,y2_,z2);
				Real d=getDis(x1,y1_,z1,x2,y2_,z2);
				add_edge(u,v,d);
			//	G[u].push_back(edge(v,d));
			//	G[v].push_back(edge(u,d));
			}
		}
	}
	for(int z=1;z<=4;z++){
		for(int x=1;x<=3;x++) for(int y=1;y<=3;y++){
			int cnt=0;
			if(exi[x][y][z]) cnt++;
			if(exi[x][y][z-1]) cnt++;
			if(cnt!=1) continue;
		//	for(int i=0;i<as.size();i++){
			for(int i=0;i<aid;i++){
				Real x1=x+as[i],y1_=y+bs[i],z1=z;
				Real x2=x+cs[i],y2_=y+ds[i],z2=z;
				int u=encode(x1,y1_,z1);
				int v=encode(x2,y2_,z2);
				Real d=getDis(x1,y1_,z1,x2,y2_,z2);
				add_edge(u,v,d);
			//	G[u].push_back(edge(v,d));
			//	G[v].push_back(edge(u,d));
			}
		}
	}
	//TODO: add edges coincide with cubes' edges
	for(int y=1;y<=4;y++) for(int z=1;z<=4;z++){
		for(int x=1;x<=3;x++){
			int cnt=0;
			for(int y_=y-1;y_<=y;y_++) for(int z_=z-1;z_<=z;z_++){
				if(exi[x][y_][z_]) cnt++;
			}
			if(cnt==0||cnt==4) continue;
			int u=encode(x,y,z);
			int v=encode(x+1,y,z);
			add_edge(u,v,1);
		//	G[u].push_back(edge(v,1));
		//	G[v].push_back(edge(u,1));
		}
	}
	for(int z=1;z<=4;z++) for(int x=1;x<=4;x++){
		for(int y=1;y<=3;y++){
			int cnt=0;
			for(int z_=z-1;z_<=z;z_++) for(int x_=x-1;x_<=x;x_++){
				if(exi[x_][y][z_]) cnt++;
			}
			if(cnt==0||cnt==4) continue;
			int u=encode(x,y,z);
			int v=encode(x,y+1,z);
			add_edge(u,v,1);
		//	G[u].push_back(edge(v,1));
		//	G[v].push_back(edge(u,1));
		}
	}
	for(int x=1;x<=4;x++) for(int y=1;y<=4;y++){
		for(int z=1;z<=3;z++){
			int cnt=0;
			for(int x_=x-1;x_<=x;x_++) for(int y_=y-1;y_<=y;y_++){
				if(exi[x_][y_][z]) cnt++;
			}
			if(cnt==0||cnt==4) continue;
			int u=encode(x,y,z);
			int v=encode(x,y,z+1);
			add_edge(u,v,1);
		//	G[u].push_back(edge(v,1));
		//	G[v].push_back(edge(u,1));
		}
	}
}

bool checkInt(int id){
	Real x=vals[id];
	int x_=(int)(x+eps);
	return eq(x,(Real)x_);
}
void init(){
	for(int i=2;i<=12;i++){
		for(int j=1;j<i;j++){
			if(gcd(i,j)!=1) continue;
			Real x=(Real)j/i;
			for(int k=1;k<=3;k++){
		//		vals.push_back(x+k);
				vals[vals_id++]=x+k;
			}
		}
	}
//	for(int k=1;k<=4;k++) vals.push_back(k);
	for(int k=1;k<=4;k++) vals[vals_id++]=k;
//	sort(vals.begin(),vals.end());
	sort(vals,vals+vals_id);
	genEdges();
//	for(int i=0;i<vals.size();i++) for(int j=0;j<vals.size();j++) for(int k=0;k<vals.size();k++){
	for(int i=0;i<vals_id;i++) for(int j=0;j<vals_id;j++) for(int k=0;k<vals_id;k++){
		int cnt=0;
		if(checkInt(i)) cnt++;
		if(checkInt(j)) cnt++;
		if(checkInt(k)) cnt++;
		if(cnt<2) continue;
//		valid_vnum.push_back(i+vals.size()*j+vals.size()*vals.size()*k);
//		valid_vnum.push_back(i+vals_id*j+vals_id*vals_id*k);
		valid_vnum[valid_vnum_id++]=i+vals_id*j+vals_id*vals_id*k;
	}
	for(int i=0;i<valid_vnum_id;i++){
		rev_valid_vnum[valid_vnum[i]]=i;
	}
//	printf("%d\n",valid_vnum.size());
//	sort(valid_vnum.begin(),valid_vnum.end());
//	sort(valid_vnum,valid_vnum+valid_vnum_id);
}

Real dis[V];

typedef pair<Real,int> State;
priority_queue<State,vector<State>,greater<State> > que;

Real solve(int x1,int y1,int z1,int x2,int y2,int z2){
//	printf("%d %d %d %d %d %d\n",x1,y1,z1,x2,y2,z2);
	int u=encode(x1,y1,z1);
	int v=encode(x2,y2,z2);
	genGraph();
//	printf("u=%d,v=%d\n",u,v);
//	int V=140*140*140;
	for(int i=0;i<V;i++){
		dis[i]=inf;
	}
	dis[u]=0;
	que.push(State(0,u));
	while(!que.empty()){
		State state = que.top();
		que.pop();
		Real cd = state.first;
		int cv = state.second;
//		printf("cv=%d\n",cv);
		if(sgn(dis[cv]-cd)>0) continue;
//		for(int i=0;i<G[cv].size();i++){
		for(int e=head[cv];e!=-1;e=nxt[e]){
		//	int nv = G[cv][i].to;
			int nv=to[e];
		//	Real nd = cd + G[cv][i].cost;
			Real nd=cd+cost[e];
			if(sgn(dis[nv]-nd)<=0) continue;
			dis[nv]=nd;
			que.push(State(nd,nv));
		}
	}
	return dis[v];
}

int x1,y1_,z1,x2,y2_,z2;

void input(){
	scanf("%d%d%d%d%d%d",&x1,&y1_,&z1,&x2,&y2_,&z2);
	if(x1==0&&y1_==0&&z1==0&&x2==0&&y2_==0&&z2==0) exit(0);
	x1++;y1_++;z1++;x2++;y2_++;z2++;
	for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) for(int k=1;k<=3;k++){
		exi[i][j][k]=false;
	}
	for(int z=1;z<=3;z++) for(int y=1;y<=3;y++){
		char ch[10];
		scanf("%s",ch+1);
		for(int x=1;x<=3;x++){
			exi[x][y][z]=ch[x]=='#';
		}
	}
}

int main(){
	init();
//	printf("%d %d\n",vals.size(),as.size());
//	int t = 0;
//	printf("as.size()=%d\n",as.size());
//	printf("valid_vnum.size()=%d\n",valid_vnum.size());
//	printf("vals.size()=%d\n",vals.size());
	while(true){
//		fprintf(stderr,"%d\n",t++);
		input();
		Real ans=solve(x1,y1_,z1,x2,y2_,z2);
		printf("%f\n",ans);
//		int s = encode(1,1,1);
//		int t = encode(4,4,4);
//		int mid = encode(1.5,1,2);
//		printf("[%d] = %f\n",s,dis[s]);
//		printf("[%d] = %f\n",t,dis[t]);
//		printf("[%d] = %f\n",mid,dis[mid]);
/*		int cnt = 0;
		for(int i = 0; i < 140*140*140;i++){
			if(dis[i] < 1e9){
				if(++cnt<=10){
					decodeAndPrint(i);
					printf("%d->%f\n",i,dis[i]);
				}
			}
		}
		exit(0);*/
	}
	return 0;
}
accuracy: 1
time_ms: 6640
memory_kb: 19988
final_rank: 5