Problem:
Problem G: Dice
サイコロ３兄弟は三つ子であり一心同体、３つでひとつとも言ってもよい。三つ子であるため見分けがつかないほど似ている。そんなサイコロ３兄弟はA君のお気に入りのおもちゃだ。A君はいつも３つ１セットでサイコロを転がして遊んでいる。このようにA君が楽しく遊ぶおもちゃだが、実は大きな秘密があった。彼らは実は生きていて、話したり自由に動いたりできるのだ。子ども部屋は
r
×
c
の大きさのグリッドで表すことができ、とても大きいものが散乱している。
サイコロ３兄弟は室内を東西南北の４方向へ進行方向に向かって転がりながら移動する。その形ゆえに斜め移動ができないのが、少し気の毒である。進行方向にとても大きいものがある場合、サイコロは進行方向に進むことができない。
サイコロ３兄弟は３つで１セットであるため、一度にひとつのサイコロしか移動することができない。また、サイコロたちはその場で回転するなどという器用な能力は持っていない。
彼らが話したり動いたりしている事実は人間には知られてはいけないというのが「おもちゃのルール」である。このルールを破ったおもちゃはこの世から消滅してしまう。A君が出かけているときに動いたり話したりしているおもちゃたちだが、A君が帰宅して子ども部屋に入ってきたときにもとの位置に戻っていなければならない。A君が帰宅した直後は緊急事態であり、A君が子ども部屋にたどり着く前にあらゆるおもちゃは即座にもとの場所へ戻らなければならない。
A君は床を見下ろすかたちになるため、サイコロの場所と上を向いている数字が正しければ、移動したことに気づくことはない。また、サイコロたちは見分けがつかないほど似ているので、どの収納場所にどのサイコロが向かっても支障はない。
そんなある日、A君のおもちゃ箱の中で最も優秀なプログラマーであるあなたに、与えられたサイコロの位置情報と収納場所から最短何手でサイコロ達が収納場所に戻れるかを計算する任務が与えられた。
サイコロ３兄弟を溺愛しているA君の手からサイコロ３兄弟が消えてしまったら、A君は泣いてしまうので、とても重要な任務である。
Input
入力は以下のフォーマットで与えられる。
r
c
grid
1
.
.
.
grid
r
grid
i
は長さ
c
の文字列で、1から6までの数字か"."か”x”か”o”からなる。
数字は収納場所かつ、到着時のサイコロの上の値を示している。
“.”は普通の床を示している。
“x”はとてもおおきなものを示している。
“o”はサイコロを示している。
入力は以下の制約を満たす
1 ≤ r,c ≤ 20
初期状態でのサイコロの向きは以下の図に従う。
Output
それぞれの入力に対する、各サイコロがすべて収納できるまでの最短手数を求めよ。
Sample Input 1
3 3
4o.
4o.
4o.
Sample Output 1
３
各サイコロが西方向に移動すればよい。
Sample Input 2
4 4
4o..
.o3.
.o..
.5..
Sample Output2
3
1行目のにあるサイコロが西方向
2行目のにあるサイコロが東方向
3行目のにあるサイコロが南方向に移動すればよい。
Sample Input 3
6 10
1xxxxxxxxx
o.......o.
xxxx.xxxx4
xoxx.xxxx.
x....3xx..
x..xxxxx..
Sample Output 3
34

Submitted solutions:

code_snippet: // AOJ #1506 Dice
// 2025.4.5

#include <bits/stdc++.h>
using namespace std;
const int INF = 10000000;

int R, C;
char g[25][25];
int goalX[3], goalY[3], goalTop[3];

int tableArr[6][4] = {
    {1, 3, 4, 2},
    {0, 2, 5, 3},
    {0, 4, 5, 1},
    {0, 1, 5, 4},
    {0, 3, 5, 2},
    {1, 2, 4, 3}
};

int moveOrientation(int idx, int dx, int dy) {
    int a = idx / 4;
    int b = idx % 4;
    int s, t;
    if(dx == -1) {
        s = tableArr[a][b];
        t = 5 - a;
    }
    else if(dx == 1) {
        s = tableArr[a][(b + 2) % 4];
        t = a;
    }
    else if(dy == -1) {
        s = tableArr[a][(b + 1) % 4];
        t = tableArr[a][b];
    }
    else {
        s = tableArr[a][(b + 3) % 4];
        t = tableArr[a][b];
    }
    int pos = 0;
    for (int i = 0; i < 4; i++) {
        if(tableArr[s][i] == t) { pos = i; break; }
    }
    return s * 4 + pos;
}

int revDist[3][25][25][24];

void computeReverseBFS(int dIdx) {
    for (int i = 0; i < R; i++)
        for (int j = 0; j < C; j++)
            for (int k = 0; k < 24; k++) revDist[dIdx][i][j][k] = INF;

    queue<vector<int>> que;
    for (int i = 0; i < 4; i++) {
        int initOri = goalTop[dIdx] * 4 + i;
        revDist[dIdx][goalX[dIdx]][goalY[dIdx]][initOri] = 0;
        vector<int> initVec = {goalX[dIdx], goalY[dIdx], initOri};
        que.push(initVec);
    }
    int dx[4] = {-1, 0, 0, 1};
    int dy[4] = {0, -1, 1, 0};
    while(!que.empty()){
        vector<int> cur = que.front();
        que.pop();
        int cx = cur[0], cy = cur[1], cori = cur[2];
        int cd = revDist[dIdx][cx][cy][cori];
        for (int i = 0; i < 4; i++) {
            int nx = cx + dx[i], ny = cy + dy[i];
            if(nx < 0 || nx >= R || ny < 0 || ny >= C) continue;
            if(g[nx][ny] == 'x') continue;
            int nori = moveOrientation(cori, dx[i], dy[i]);
            if(revDist[dIdx][nx][ny][nori] > cd + 1) {
                revDist[dIdx][nx][ny][nori] = cd + 1;
                vector<int> nextVec = {nx, ny, nori};
                que.push(nextVec);
            }
        }
    }
}

typedef vector<vector<int>> StateType;

struct StateHash {
    size_t operator()(const StateType &state) const {
        size_t seed = 0;
        for (size_t i = 0; i < state.size(); i++)
            for (size_t j = 0; j < state[i].size(); j++)
                seed ^= std::hash<int>()(state[i][j]) + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);
        return seed;
    }
};

int heuristic(const StateType &state) {
    int perms[6][3] = {
        {0, 1, 2},
        {0, 2, 1},
        {1, 0, 2},
        {1, 2, 0},
        {2, 0, 1},
        {2, 1, 0}
    };
    int best = INF;
    for (int p = 0; p < 6; p++) {
        int sum = 0;
        for (int i = 0; i < 3; i++) {
            int dIdx = perms[p][i];
            int x = state[i][0], y = state[i][1], ori = state[i][2];
            sum += revDist[dIdx][x][y][ori];
        }
        best = min(best, sum);
    }
    return best;
}

bool isGoal(const StateType &state) {
    int perms[6][3] = {
        {0, 1, 2},
        {0, 2, 1},
        {1, 0, 2},
        {1, 2, 0},
        {2, 0, 1},
        {2, 1, 0}
    };
    for (int p = 0; p < 6; p++) {
        bool ok = true;
        for (int i = 0; i < 3; i++) {
            int dIdx = perms[p][i];
            if(state[i][0] != goalX[dIdx] || state[i][1] != goalY[dIdx] || (state[i][2] / 4) != goalTop[dIdx]) {
                ok = false;
                break;
            }
        }
        if(ok) return true;
    }
    return false;
}

struct Node {
    int f, g, h;
    StateType state;
};

struct NodeComp {
    bool operator()(const Node &a, const Node &b) const {
        return a.f > b.f;
    }
};

int main(){
    cin >> R >> C;
    for (int i = 0; i < R; i++) for (int j = 0; j < C; j++) cin >> g[i][j];

    int cnt = 0;
    for (int i = 0; i < R; i++) {
        for (int j = 0; j < C; j++) {
            if(g[i][j] >= '1' && g[i][j] <= '6'){
                if(cnt < 3) {
                    goalX[cnt] = i;
                    goalY[cnt] = j;
                    goalTop[cnt] = g[i][j] - '1';
                    cnt++;
                }
            }
        }
    }
    for (int dIdx = 0; dIdx < 3; dIdx++) computeReverseBFS(dIdx);

    StateType initState;
    for (int i = 0; i < R; i++) {
        for (int j = 0; j < C; j++) {
            if(g[i][j] == 'o'){
                vector<int> temp = {i, j, 0};
                initState.push_back(temp);
            }
        }
    }
    sort(initState.begin(), initState.end());

    unordered_map<StateType, int, StateHash> bestCost;
    priority_queue<Node, vector<Node>, NodeComp> pq;
    int h0 = heuristic(initState);
    Node start;
    start.g = 0;
    start.h = h0;
    start.f = h0;
    start.state = initState;
    pq.push(start);
    bestCost[initState] = 0;

    int dx[4] = {-1, 0, 0, 1};
    int dy[4] = {0, -1, 1, 0};
    while(!pq.empty()){
        Node cur = pq.top();
        pq.pop();
        if(bestCost[cur.state] < cur.g) continue;
        if(isGoal(cur.state)) {
            cout << cur.g << endl;
            return 0;
        }
        for (int i = 0; i < 3; i++) {
            for (int d = 0; d < 4; d++){
                int nx = cur.state[i][0] + dx[d];
                int ny = cur.state[i][1] + dy[d];
                if(nx < 0 || nx >= R || ny < 0 || ny >= C) continue;
                if(g[nx][ny] == 'x') continue;
                int nori = moveOrientation(cur.state[i][2], dx[d], dy[d]);
                StateType nextState = cur.state;
                nextState[i] = {nx, ny, nori};
                bool collision = false;
                for (int j = 0; j < 3; j++) {
                    for (int k = j+1; k < 3; k++){
                        if(nextState[j][0] == nextState[k][0] && nextState[j][1] == nextState[k][1]){
                            collision = true;
                            break;
                        }
                    }
                    if(collision) break;
                }
                if(collision) continue;
                sort(nextState.begin(), nextState.end());
                int newG = cur.g + 1;
                if(bestCost.find(nextState) == bestCost.end() || bestCost[nextState] > newG) {
                    bestCost[nextState] = newG;
                    int hval = heuristic(nextState);
                    Node nxt;
                    nxt.g = newG;
                    nxt.h = hval;
                    nxt.f = newG + hval;
                    nxt.state = nextState;
                    pq.push(nxt);
                }
            }
        }
    }
    cout << -1 << endl;
    return 0;
}
accuracy: 1
time_ms: 370
memory_kb: 85812
final_rank: 1

code_snippet: // AOJ #1506 Dice
// 2025.4.5

#include <bits/stdc++.h>
using namespace std;

const int INF = 1000000;

int n, m;
char g[25][25];
int goalX[3], goalY[3], goalTop[3];

int tableArr[6][4] = {
    {1, 3, 4, 2},
    {0, 2, 5, 3},
    {0, 4, 5, 1},
    {0, 1, 5, 4},
    {0, 3, 5, 2},
    {1, 2, 4, 3}
};

int moveOrientation(int idx, int dx, int dy) {
    int a = idx / 4;
    int b = idx % 4;
    int s, t;
    if(dx == -1) {
        s = tableArr[a][b];
        t = 5 - a;
    } else if(dx == 1) {
        s = tableArr[a][(b + 2) % 4];
        t = a;
    } else if(dy == -1) {
        s = tableArr[a][(b + 1) % 4];
        t = tableArr[a][b];
    } else {
        s = tableArr[a][(b + 3) % 4];
        t = tableArr[a][b];
    }
    int pos = 0;
    for (int i = 0; i < 4; i++) {
        if(tableArr[s][i] == t) { pos = i; break; }
    }
    return s * 4 + pos;
}

int revDist[3][25][25][24];

void computeReverseBFS(int dIdx) {
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            for (int k = 0; k < 24; k++) revDist[dIdx][i][j][k] = INF;
    queue< vector<int> > que;
    for (int i = 0; i < 4; i++) {
        int initOri = goalTop[dIdx] * 4 + i;
        revDist[dIdx][goalX[dIdx]][goalY[dIdx]][initOri] = 0;
        vector<int> initVec = {goalX[dIdx], goalY[dIdx], initOri};
        que.push(initVec);
    }
    int dx[4] = {-1, 0, 0, 1};
    int dy[4] = {0, -1, 1, 0};
    while(!que.empty()){
        vector<int> cur = que.front();
        que.pop();
        int cx = cur[0], cy = cur[1], cori = cur[2];
        int cd = revDist[dIdx][cx][cy][cori];
        for (int i = 0; i < 4; i++) {
            int nx = cx + dx[i], ny = cy + dy[i];
            if(nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
            if(g[nx][ny] == 'x') continue;
            int nori = moveOrientation(cori, dx[i], dy[i]);
            if(revDist[dIdx][nx][ny][nori] > cd + 1) {
                revDist[dIdx][nx][ny][nori] = cd + 1;
                vector<int> nextVec = {nx, ny, nori};
                que.push(nextVec);
            }
        }
    }
}

typedef vector<vector<int>> StateType;

int heuristic(const StateType &state) {
    int perms[6][3] = {
        {0, 1, 2},
        {0, 2, 1},
        {1, 0, 2},
        {1, 2, 0},
        {2, 0, 1},
        {2, 1, 0}
    };
    int best = INF;
    for (int p = 0; p < 6; p++) {
        int sum = 0;
        for (int i = 0; i < 3; i++) {
            int dIdx = perms[p][i];
            int x = state[i][0], y = state[i][1], ori = state[i][2];
            sum += revDist[dIdx][x][y][ori];
        }
        best = min(best, sum);
    }
    return best;
}

bool isGoal(const StateType &state) {
    int perms[6][3] = {
        {0, 1, 2},
        {0, 2, 1},
        {1, 0, 2},
        {1, 2, 0},
        {2, 0, 1},
        {2, 1, 0}
    };
    for (int p = 0; p < 6; p++) {
        bool ok = true;
        for (int i = 0; i < 3; i++) {
            int dIdx = perms[p][i];
            if(state[i][0] != goalX[dIdx] || state[i][1] != goalY[dIdx] || (state[i][2] / 4) != goalTop[dIdx]) {
                ok = false;
                break;
            }
        }
        if(ok) return true;
    }
    return false;
}

struct Node {
    int f, g, h;
    StateType state;
};

struct NodeComp {
    bool operator()(const Node &a, const Node &b) const {
        return a.f > b.f;
    }
};

int main(){
    cin >> n >> m;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++) cin >> g[i][j];

    int cnt = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if(g[i][j] >= '1' && g[i][j] <= '6'){
                if(cnt < 3) {
                    goalX[cnt] = i;
                    goalY[cnt] = j;
                    goalTop[cnt] = g[i][j] - '1';
                    cnt++;
                }
            }
        }
    }
    for (int dIdx = 0; dIdx < 3; dIdx++) computeReverseBFS(dIdx);

    StateType initState;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if(g[i][j] == 'o'){
                vector<int> temp = {i, j, 0};
                initState.push_back(temp);
            }
        }
    }
    sort(initState.begin(), initState.end());

    map<StateType, int> bestCost;
    priority_queue<Node, vector<Node>, NodeComp> pq;
    int h0 = heuristic(initState);
    Node start;
    start.g = 0;
    start.h = h0;
    start.f = h0;
    start.state = initState;
    pq.push(start);
    bestCost[initState] = 0;

    int dx[4] = {-1, 0, 0, 1};
    int dy[4] = {0, -1, 1, 0};
    while(!pq.empty()){
        Node cur = pq.top();
        pq.pop();
        if(bestCost[cur.state] < cur.g) continue;
        if(isGoal(cur.state)) {
            cout << cur.g << endl;
            return 0;
        }
        for (int i = 0; i < 3; i++) {
            for (int d = 0; d < 4; d++){
                int nx = cur.state[i][0] + dx[d];
                int ny = cur.state[i][1] + dy[d];
                if(nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
                if(g[nx][ny] == 'x') continue;
                int nori = moveOrientation(cur.state[i][2], dx[d], dy[d]);
                StateType nextState = cur.state;
                nextState[i] = {nx, ny, nori};
                bool collision = false;
                for (int j = 0; j < 3; j++) {
                    for (int k = j+1; k < 3; k++){
                        if(nextState[j][0] == nextState[k][0] && nextState[j][1] == nextState[k][1]){
                            collision = true;
                            break;
                        }
                    }
                    if(collision) break;
                }
                if(collision) continue;
                sort(nextState.begin(), nextState.end());
                int newG = cur.g + 1;
                if(bestCost.find(nextState) == bestCost.end() || bestCost[nextState] > newG) {
                    bestCost[nextState] = newG;
                    int hval = heuristic(nextState);
                    Node nxt;
                    nxt.g = newG;
                    nxt.h = hval;
                    nxt.f = newG + hval;
                    nxt.state = nextState;
                    pq.push(nxt);
                }
            }
        }
    }
    cout << -1 << endl;
    return 0;
}
accuracy: 1
time_ms: 530
memory_kb: 85856
final_rank: 2

code_snippet: #include <cstdio>
#include <algorithm>
#include <queue>
#include <map>
#include <memory>

#define rep(i, n) for(int i = 0; i < n; ++i)

using namespace std;

typedef vector<vector<int>> R;
typedef shared_ptr<R> Q;
typedef pair<pair<int, int>, Q> P;

int table[6][4] = {
	{1, 3, 4, 2},
	{0, 2, 5, 3},
	{0 ,4, 5, 1},
	{0, 1, 5, 4},
	{0, 3, 5, 2},
	{1, 2, 4, 3}
};

int move(int index, int dx, int dy){
	int a = index / 4;
	int b = index % 4;
	int s, t;
	if(dx == -1){
		s = table[a][b];
		t = 5 - a;
	}
	else if(dx == 1){
		s = table[a][(b + 2) % 4];
		t = a;
	}
	else if(dy == -1){
		s = table[a][(b + 1) % 4];
		t = table[a][b];
	}
	else{
		s = table[a][(b + 3) % 4];
		t = table[a][b];
	}
	return s * 4 + find(table[s], table[s] + 4, t) - table[s];
}

int n ,m;
char g[20][20];
int sx[3];
int sy[3];
int st[3];
int d[3][20][20][24];
map<vector<vector<int>>, int> f;

int approximate(vector<vector<int>>& t){
	int p[6][3] = {
		{0, 1, 2},
		{0, 2, 1},
		{1, 0, 2},
		{1, 2, 0},
		{2, 0, 1},
		{2, 1, 0}
	};

	int u = -1;
	rep(i, 6){
		int v = d[p[i][0]][t[0][0]][t[0][1]][t[0][2]] + d[p[i][1]][t[1][0]][t[1][1]][t[1][2]] + d[p[i][2]][t[2][0]][t[2][1]][t[2][2]];
		if(u == -1 || u > v){
			u = v;
		}
	}
	return u;
}

bool is_reached(vector<vector<int>>& t){
	int p[6][3] = {
		{0, 1, 2},
		{0, 2, 1},
		{1, 0, 2},
		{1, 2, 0},
		{2, 0, 1},
		{2, 1, 0}
	};

	rep(a, 6){
		bool b = true;
		rep(i, 3){
			if(!(t[i][0] == sx[p[a][i]] && t[i][1] == sy[p[a][i]] && t[i][2] / 4 == st[p[a][i]])){
				b = false;
			}
		}
		if(b){
			return true;
		}
	}
	return false;
}

int main(){
	scanf("%d%d", &n, &m);
	rep(i, n){
		rep(j, m){
			scanf(" %c", &g[i][j]);
		}
	}

	int t = 0;
	rep(i, n){
		rep(j, m){
			if('1' <= g[i][j] && g[i][j] <= '6'){
				sx[t] = i;
				sy[t] = j;
				st[t] = g[i][j] - '1';
				++t;
			}
		}
	}
	rep(a, 3){
		rep(i, n){
			rep(j, m){
				rep(k, 24){
					d[a][i][j][k] = 10000;
				}
			}
		}

		queue<vector<int>> q;
		rep(i, 4){
			d[a][sx[a]][sy[a]][st[a] * 4 + i] = 0;
			q.push({sx[a], sy[a], st[a] * 4 + i});
		}
		while(!q.empty()){
			auto v = q.front();
			q.pop();
			int dx[4] = {-1, 0, 0, 1};
			int dy[4] = {0, -1, 1, 0};
			rep(i, 4){
				int x = v[0] + dx[i];
				int y = v[1] + dy[i];
				int index = move(v[2], dx[i], dy[i]);
				if(0 <= x && x < n && 0 <= y && y < m && g[x][y] != 'x' && d[a][x][y][index] == 10000){
					d[a][x][y][index] = d[a][v[0]][v[1]][v[2]] + 1;
					q.push({x, y, index});
				}
			}
		}
	}

	priority_queue<P, vector<P>, greater<P>> q;
	vector<vector<int>> s;
	rep(i, n){
		rep(j, m){
			if(g[i][j] == 'o'){
				s.push_back({i, j, 0});
			}
		}
	}
	q.push({{approximate(s), approximate(s)}, Q(new R(s))});
	while(!q.empty()){
		/*
		printf("(%d, %d)\n", q.top().first.first, q.top().first.second);
		*/

		auto v = *q.top().second;
		q.pop();
		int dx[4] = {-1, 0, 0, 1};
		int dy[4] = {0, -1, 1, 0};
		rep(a, 3){
			rep(i, 4){
				int x = v[a][0] + dx[i];
				int y = v[a][1] + dy[i];
				int index = move(v[a][2], dx[i], dy[i]);
				auto t = v;
				t[a][0] = x;
				t[a][1] = y;
				t[a][2] = index;
				bool b = true;
				rep(j, 3){
					if(v[j][0] == x && v[j][1] == y){
						b = false;
					}
				}
				if(0 <= x && x < n && 0 <= y && y < m && g[x][y] != 'x' && b && f.find(t) == f.end()){
					f[t] = f[v] + 1;
					if(is_reached(t)){
						printf("%d\n", f[t]);
						return 0;
					}
					q.push({{approximate(t) + f[t], approximate(t)}, Q(new R(t))});
				}
			}
		}
	}
	return 0;
}
accuracy: 1
time_ms: 1270
memory_kb: 172316
final_rank: 3

code_snippet: #include<iostream>
#include<queue>
#include<algorithm>
#include<vector>
#include<ctime>
#include<cstdio>
#include<map>
#include<set>

using namespace std;

class Dice{
public:
   int x,y;
   int C[3];
   Dice(int c0,int c1,int c2,int _x,int _y){
      C[0] = c0;
      C[1] = c1;
      C[2] = c2;
      x = _x;
      y = _y;
   };
   Dice(){};
   void rotate_left(){
      swap(C[0],C[2]);
      C[2] = 7 - C[2];
   }
   void rotate_right(){
      swap(C[0],C[2]);
      C[0] = 7 - C[0];
   }
   void rotate_front(){
      swap(C[0],C[1]);
      C[0] = 7 - C[0];
   }
   void rotate_back(){
      swap(C[0],C[1]);
      C[1] = 7 - C[1];
   }
   void rotate(){
      swap(C[1],C[2]);
      C[1] = 7 - C[1];
   }
   bool operator < (const Dice &d)const {
      return false;
   }
};

class Status{
public:
   int state[3],x[3],y[3];
   Status(){};
   Status(int s0,int y0,int x0,int s1,int y1,int x1,int s2,int y2,int x2){
      state[0] = s0;
      x[0] = x0;
      y[0] = y0;
      state[1] = s1;
      x[1] = x1;
      y[1] = y1;
      state[2] = s2;
      x[2] = x2;
      y[2] = y2;
   };
   bool operator < (const Status &s)const {
      for(int i = 0 ; i < 3 ; i++){
	 if(state[i] != s.state[i])return state[i] < s.state[i];
	 if(x[i] != s.x[i])return x[i] < s.x[i];
	 if(y[i] != s.y[i])return y[i] < s.y[i];
      }
      return false;
   }
};

Dice allState[24];
int indexState[7][7][7];

void createAll(){
   Dice dice(1,2,4,0,0);
   for(int i = 0 ; i < 6 ; i++){
      for(int j = 0 ; j < 4 ; j++){
         allState[i*4+j] = dice;
         indexState[dice.C[0]][dice.C[1]][dice.C[2]] = i*4+j;
         dice.rotate();
      }
      if(i%2)dice.rotate_front();
      else dice.rotate_right();
   }
}

int H,W;
const int MAX = 20;
const int INF = 1e8;
char data[MAX][MAX];
int h[3][24][MAX][MAX];
vector<Dice>ini;
void init(){
   ini.clear();
   for(int i = 0 ; i < 3 ; i++){
      for(int j = 0 ; j < 24 ; j++){
         for(int k = 0 ; k < MAX ; k++){
	    for(int l = 0 ; l < MAX ; l++){
	       h[i][j][k][l] = INF;
	    }
         }
      }
   }
}

typedef pair<int,vector<Dice> > PP;
typedef pair<int,PP > PP2;
typedef pair<int,int>P;
typedef pair<int,P>P2;

void input(){
   for(int i = 0 ; i < H ; i++){
      for(int j = 0 ; j < W ; j++){
         cin >> data[i][j];
         if(data[i][j] == 'o'){
            ini.push_back(Dice(1,2,4,j,i));
         }
      }
   }
}

int dx[4] = {0,1,0,-1};
int dy[4] = {-1,0,1,0};

bool isOK(vector<Dice>vec){
   for(int i = 0 ; i < 3 ; i++){
      if(!isdigit(data[vec[i].y][vec[i].x]))return false;
      if(vec[i].C[0] != data[vec[i].y][vec[i].x] - '0')return false;
   }
   return true;
}

int heuristic(int cnt,vector<Dice> vec){
   int res = INF;
   int index[3] = {0,1,2};

   int s[3];
   s[0] = indexState[vec[0].C[0]][vec[0].C[1]][vec[0].C[2]];
   s[1] = indexState[vec[1].C[0]][vec[1].C[1]][vec[1].C[2]];
   s[2] = indexState[vec[2].C[0]][vec[2].C[1]][vec[2].C[2]];

   do{
      res = min(res,cnt + h[index[0]][s[0]][vec[0].y][vec[0].x] + h[index[1]][s[1]][vec[1].y][vec[1].x] + h[index[2]][s[2]][vec[2].y][vec[2].x]);
   }while(next_permutation(index,index + 3));

   return res;
}

bool check(P p){
   if(!(0 <= p.first && p.first < H))return true;
   if(!(0 <= p.second && p.second < W))return true;
   return false;
}

void solve(){
   
   priority_queue<PP2,vector<PP2>,greater<PP2> >que;
   vector<Dice>vec;
   
   que.push(PP2(heuristic(0,ini),PP(0,ini)));
   map<Status,int>vis;

   vis[Status(indexState[ini[0].C[0]][ini[0].C[1]][ini[0].C[2]],ini[0].y,ini[0].x,
	      indexState[ini[1].C[0]][ini[1].C[1]][ini[1].C[2]],ini[1].y,ini[1].x,
	      indexState[ini[2].C[0]][ini[2].C[1]][ini[2].C[2]],ini[2].y,ini[2].x)] = 0;

      
   while(que.size()){
      PP2 pp2 = que.top(); que.pop();
      
      int cnt = pp2.second.first * -1;
      vec = pp2.second.second;

      int H = pp2.first;

      for(int i = 0 ; i < 3 ; i++){
         for(int j = 0 ; j < 4 ; j++){
            vector<Dice> nvec = vec;	    
            
            nvec[i].x = nvec[i].x + dx[j];
            nvec[i].y = nvec[i].y + dy[j];
            
            switch(j){
               case 0:
                  nvec[i].rotate_back();
                  break;
               case 1:
                  nvec[i].rotate_right();
                  break;
               case 2:
                  nvec[i].rotate_front();
                  break;
               case 3:
                  nvec[i].rotate_left();
                  break;
            }
            
            if(data[nvec[i].y][nvec[i].x] == 'x')continue;
	    if(check(P(nvec[i].y,nvec[i].x)))continue;
	    bool iscollide = false;
	    for(int k = 0 ; k < 3; k++){
	       if(i == k)continue;
	       if(nvec[i].y == nvec[k].y && nvec[i].x == nvec[k].x)iscollide = true;
	    }

	    if(iscollide)continue;
	    if(isOK(nvec)){
	       cout << cnt+1 << endl;
	       return;
	    }

	    Status nstatus = Status(indexState[nvec[0].C[0]][nvec[0].C[1]][nvec[0].C[2]],nvec[0].y,nvec[0].x,
				    indexState[nvec[1].C[0]][nvec[1].C[1]][nvec[1].C[2]],nvec[1].y,nvec[1].x,
				    indexState[nvec[2].C[0]][nvec[2].C[1]][nvec[2].C[2]],nvec[2].y,nvec[2].x);

	    if(vis.find(nstatus) == vis.end() || vis[nstatus] > cnt){
	       vis[nstatus] = cnt;
	       que.push(PP2(heuristic(cnt+1,nvec),PP((cnt+1)*-1,nvec)));
	    }
         }
      }
   }
   cout << "error" << endl;//
}


typedef pair<int,Dice> P3;


void bfs(P p,int id){

   queue<P3>que;
   Dice dice;

   for(int i = 0 ; i < 24 ; i++){
      dice =  allState[i];
      if(data[p.first][p.second] - '0' == dice.C[0]){
	 dice.y = p.first;
	 dice.x = p.second;
	 h[id][indexState[dice.C[0]][dice.C[1]][dice.C[2]]][dice.y][dice.x] = 0;
	 que.push(P3(0,dice));
      }
   }

   while(que.size()){
      P3 p3 = que.front(); que.pop();
      int cnt = p3.first;
      dice = p3.second;
      for(int i = 0 ; i < 4 ; i++){      
	 Dice ndice = dice;
	 ndice.x += dx[i];
	 ndice.y += dy[i];

	 switch(i){
	    case 0:
	       ndice.rotate_back();
	       break;
	    case 1:
	       ndice.rotate_right();
	       break;
	    case 2:
	       ndice.rotate_front();
	       break;
	    case 3:
	       ndice.rotate_left();
	       break;
	 }

	 if(check(P(ndice.y,ndice.x)))continue;
         if(data[ndice.y][ndice.x] == 'x')continue;
	 int ns = indexState[ndice.C[0]][ndice.C[1]][ndice.C[2]];
         if(h[id][ns][ndice.y][ndice.x] == INF){
            h[id][ns][ndice.y][ndice.x] = cnt+1;
            que.push(P3(cnt+1,ndice));
         }
      }
   }
}

int main(){
   createAll();
   int cnt = 1;
   cin >> H >> W;
   init();
   input();
   int id = 0;
   for(int i = 0 ; i < H ; i++){
     for(int j = 0 ; j < W ; j++){
       if(isdigit(data[i][j]))bfs(P(i,j),id++);
     }
   }
   solve();
   return 0;
}
accuracy: 1
time_ms: 2590
memory_kb: 189632
final_rank: 4