Problem:
Problem G:
Time Trial
Some people like finishing computer games in an extremely short time. Terry A. Smith is one of such
and prefers role playing games particularly.
He is now trying to find a shorter play for one of the key events in a role playing game. In this event,
a player is presented a kind of puzzle on a grid map with three rocks and three marked squares. The
objective is to have all the rocks placed on the marked squares by controlling the hero of this game
appropriately.
Figure 1: Example Map
The hero can move to the four adjacent squares, that is, to the north, east, south, and west, unless his move
is blocked by walls or rocks. He can never enter squares occupied by walls. On the other hand, when he
is moving to a square occupied by a rock, he pushes the rock in his moving direction. Nonetheless, he
cannot push the rock if the next square is occupied by a wall or another rock and his move is blocked in
this case. Also, he can only move one rock at a time. It is allowed to have rocks pass through marked
squares.
Terry thinks he can reduce his playing time by finding the optimal way to move the rocks and then playing
the event accordingly. However, it is too hard for him to find the solution of this puzzle by hand. So you
are asked by him to write a program that finds the smallest number of steps for the maps given as the
input. Here, each move from a square to its adjacent square is counted as one step.
Input
The input is a sequence of datasets. Each dataset has the following format:
W H
Row
1
...
Row
H
W
and
H
are the width and height of the map (4 ≤
W
,
H
≤ 16).
Row
i
denotes the
i
-th row of the map
and consists of
W
characters. Each character represents a square and is one of the following: ‘
#
’ (wall), ‘
.
’ (floor), ‘
*
’ (rock), ‘
_
’ (marked square), and ‘
@
’ (hero). Each map contains exactly three rocks, three
marked squares, and one hero. The outermost squares are always occupied by walls. You may assume
that the number of non-wall squares does not exceed fifty. It is also guaranteed that there is at least one
solution for every map.
The input is terminated by a line with two zeros. This line is not part of any datasets and should not be
processed.
Output
For each dataset, print the smallest number of steps in a line.
Sample Input
7 6
#######
#.._..#
#.*.*.#
#.@.*.#
#_..._#
#######
10 13
##########
####___###
####...###
####...###
#####.####
#.....#..#
#.#*.*.*.#
#...###..#
###.#.#.##
###.#.#.##
###.....##
###..@..##
##########
0 0
Output for the Sample Input
15
118

Submitted solutions:

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ll myRand(ll B) { return (ull)rng() % B; }

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

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int w, h;
    while (cin >> w >> h, h) {
        int n = 0;
        vector<vector<int>> idx(h + 2, vector<int>(w + 2, -1));
        int init;
        vector<int> init_rock, goal;
        using P = pair<int, int>;
        vector<P> pos;
        for (int i = 1; i <= h; ++i) {
            string s;
            cin >> s;
            s = "?" + s;
            for (int j = 1; j <= w; ++j) {
                if (s[j] == '#') continue;
                idx[i][j] = n++;
                pos.push_back({i, j});
                if (s[j] == '@') init = {idx[i][j]};
                if (s[j] == '*') init_rock.push_back(idx[i][j]);
                if (s[j] == '_') goal.push_back(idx[i][j]);
            }
        }
        memset(dp, -1, sizeof(dp));

        vector<int> ex(n, -1);
        dp[init][init_rock[0]][init_rock[1]][init_rock[2]] = 0;
        queue<tuple<int, int, int, int>> q;
        q.push({init, init_rock[0], init_rock[1], init_rock[2]});
        int res = 1e9, uid = -1;
        while (q.size()) {
            auto [cur, p1, p2, p3] = q.front();
            q.pop();
            uid += 1;
            int cost = dp[cur][p1][p2][p3];
            if (p1 == goal[0] and p2 == goal[1] and p3 == goal[2]) {
                res = cost;
                break;
            }
            auto [x, y] = pos[cur];

            ex[p1] = ex[p2] = ex[p3] = uid;
            for (int i = 0; i < 4; ++i) {
                int nx = x + dx[i];
                int ny = y + dy[i];
                // 壁には侵入出来ない
                if (idx[nx][ny] == -1) continue;
                int id = idx[nx][ny];
                // 石が無い場合はそのまま進める
                if (ex[id] != uid) {
                    if (dp[id][p1][p2][p3] == -1) {
                        dp[id][p1][p2][p3] = cost + 1;
                        q.push({id, p1, p2, p3});
                    }
                } else {
                    vector<int> pp;
                    if (p1 != id) pp.push_back(p1);
                    if (p2 != id) pp.push_back(p2);
                    if (p3 != id) pp.push_back(p3);
                    nx += dx[i], ny += dy[i];
                    int iid = idx[nx][ny];
                    if (iid != -1 and ex[iid] != uid) {
                        pp.push_back(iid);
                        sort(pp.begin(), pp.end());
                        if (dp[id][pp[0]][pp[1]][pp[2]] == -1) {
                            dp[id][pp[0]][pp[1]][pp[2]] = cost + 1;
                            q.push({id, pp[0], pp[1], pp[2]});
                        }
                    }
                }
            }
        }
        cout << res << "\n";
    }
}
accuracy: 1
time_ms: 180
memory_kb: 28368
final_rank: 5

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ll myRand(ll B) { return (ull)rng() % B; }

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

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int w, h;
    while (cin >> w >> h, h) {
        int n = 0;
        vector<vector<int>> idx(h + 2, vector<int>(w + 2, -1));
        int init;
        vector<int> init_rock, goal;
        using P = pair<int, int>;
        vector<P> pos;
        for (int i = 1; i <= h; ++i) {
            string s;
            cin >> s;
            s = "?" + s;
            for (int j = 1; j <= w; ++j) {
                if (s[j] == '#') continue;
                idx[i][j] = n++;
                pos.push_back({i, j});
                if (s[j] == '@') init = {idx[i][j]};
                if (s[j] == '*') init_rock.push_back(idx[i][j]);
                if (s[j] == '_') goal.push_back(idx[i][j]);
            }
        }

        vector<int> ex(n, -1);
        map<tuple<int, int, int, int>, int> mp;
        mp[{init, init_rock[0], init_rock[1], init_rock[2]}] = 0;
        queue<tuple<int, int, int, int>> q;
        q.push({init, init_rock[0], init_rock[1], init_rock[2]});
        int res = 1e9, uid = -1;
        while (q.size()) {
            auto [cur, p1, p2, p3] = q.front();
            q.pop();
            uid += 1;
            int cost = mp[{cur, p1, p2, p3}];
            if (p1 == goal[0] and p2 == goal[1] and p3 == goal[2]) {
                res = cost;
                break;
            }
            auto [x, y] = pos[cur];

            ex[p1] = ex[p2] = ex[p3] = uid;
            for (int i = 0; i < 4; ++i) {
                int nx = x + dx[i];
                int ny = y + dy[i];
                // 壁には侵入出来ない
                if (idx[nx][ny] == -1) continue;
                int id = idx[nx][ny];
                // 石が無い場合はそのまま進める
                if (ex[id] != uid) {
                    if (mp.find({id, p1, p2, p3}) == mp.end()) {
                        mp[{id, p1, p2, p3}] = cost + 1;
                        q.push({id, p1, p2, p3});
                    }
                } else {
                    vector<int> pp;
                    if (p1 != id) pp.push_back(p1);
                    if (p2 != id) pp.push_back(p2);
                    if (p3 != id) pp.push_back(p3);
                    nx += dx[i], ny += dy[i];
                    int iid = idx[nx][ny];
                    if (iid != -1 and ex[iid] != uid) {
                        pp.push_back(iid);
                        sort(pp.begin(), pp.end());
                        if (mp.find({id, pp[0], pp[1], pp[2]}) == mp.end()) {
                            mp[{id, pp[0], pp[1], pp[2]}] = cost + 1;
                            q.push({id, pp[0], pp[1], pp[2]});
                        }
                    }
                }
            }
        }
        cout << res << "\n";
    }
}
accuracy: 1
time_ms: 2330
memory_kb: 29328
final_rank: 9

code_snippet: #include <bits/stdc++.h>
 
using namespace std;
 
#define MAX 16
 
int H,W,gp[MAX*MAX];
char field[MAX][MAX];
const int dx[4] = {-1,0,1,0};
const int dy[4] = {0,-1,0,1};
 
struct State{
    int h,r[3];
};
 
inline bool check(const State &s){
    for(int i = 0 ; i < 3 ; i++){
	if(field[s.r[i]/W][s.r[i]%W] != '_'){
	    return false;
	}
    }
    return true;
}
 
inline int canMove(const State &s,int &dir){
    if(field[s.h/W][s.h%W] == '#') return -1;
    int idx = -1;
    for(int i = 0 ; i < 3 ; i++){
	if(s.h == s.r[i]){
	    idx = i; break;
	}
    }
    if(idx == -1) return 3;
    int nx = s.h%W + dx[dir];
    int ny = s.h/W + dy[dir];
    if(field[ny][nx] == '#') return -1;
    for(int i = 0 ; i < 3 ; i++){
	if(i == idx) continue;
	if(s.r[i]%W == nx && s.r[i]/W == ny){
	    return -1;
	}
    }
    return idx;
}
 
bool visited[50][50][50][50];
 
int bfs(const State &S){
    queue<State> Q; Q.push(S);
    queue<int> step; step.push(0);
    const int dr[4] = {-1,-W,1,W};
    memset(visited,false,sizeof(visited));
    visited[gp[S.h]][gp[S.r[0]]][gp[S.r[1]]][gp[S.r[2]]] = true;
 
    while(!Q.empty()){
	State s = Q.front(); Q.pop();
	int st = step.front(); step.pop();
	if(check(s)) return st;
	for(int i = 0 ; i < 4 ; i++){
	    s.h += dr[i];
	    int r = canMove(s,i);
	    if(r == -1){
		s.h -= dr[i];
		continue;
	    }
	    if(r == 3){
		if(!visited[gp[s.h]][gp[s.r[0]]][gp[s.r[1]]][gp[s.r[2]]]){
		    visited[gp[s.h]][gp[s.r[0]]][gp[s.r[1]]][gp[s.r[2]]] = true;
		    Q.push(s);
		    step.push(st+1);
		}
	    }else{
		s.r[r] += dr[i];
		if(!visited[gp[s.h]][gp[s.r[0]]][gp[s.r[1]]][gp[s.r[2]]]){
		    visited[gp[s.h]][gp[s.r[0]]][gp[s.r[1]]][gp[s.r[2]]] = true;
		    Q.push(s);
		    step.push(st+1);
		}
		s.r[r] -= dr[i];
	    }
	    s.h -= dr[i];
	}
    }
    return -1;
}
 
int main(){
    while(cin >> W >> H,(W|H)){
	int r = 0,idx = 0;
	State start;
	for(int i = 0 ; i < H ; i++){
	    for(int j = 0 ; j < W ; j++){
		cin >> field[i][j];
		if(field[i][j] == '@'){
		    start.h = i*W+j;
		}else if(field[i][j] == '*'){
		    start.r[r++] = i*W+j;
		}
		if(field[i][j] != '#'){
		    gp[i*W+j] = idx++;
		}
	    }
	}
	cout << bfs(start) << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 290
memory_kb: 10968
final_rank: 2

code_snippet: #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<list>
#include<queue>
#include<deque>
#include<algorithm>
#include<numeric>
#include<utility>
#include<complex>
#include<functional>
 
using namespace std;

/* constant */

const int MAX_W = 16;
const int MAX_H = 16;
const int MAX_V = 50;
const int INF = 1 << 30;

/* typedef */

struct Stat {
  int vi, rs[3];
  Stat(int _vi, int _rs[]) {
    vi = _vi; rs[0] = _rs[0]; rs[1] = _rs[1]; rs[2] = _rs[2];
  }
};

typedef vector<int> vi;
typedef long long ll;

/* global variables */

int w, h;
string flds[MAX_H];
int vn, vs[MAX_V], nbrs[MAX_V][4];
int sv, rvs[3], mvs[3], ri, mi;

int dpos[] = {1, 0, -1, 0};
int dists[MAX_V][MAX_V][MAX_V][MAX_V];

/* subroutines */

/* main */

int main() {
  for (;;) {
    cin >> w >> h;
    if (w == 0) break;

    for (int i = 0; i < h; i++) cin >> flds[i];

    vn = ri = mi = 0;
    for (int y = 0; y < h; y++)
      for (int x = 0; x < w; x++) {
	char ch = flds[y][x];
	if (ch == '#') continue;

	switch (ch) {
	case '*': rvs[ri++] = vn; break;
	case '_': mvs[mi++] = vn; break;
	case '@': sv = vn; break;
	}

      	int pos = y * w + x;
	vs[vn++] = pos;
      }

    dpos[1] = -w, dpos[3] = w;

    for (int vi = 0; vi < vn; vi++)
      for (int di = 0; di < 4; di++) {
	int pos = vs[vi] + dpos[di];
	int nvi = lower_bound(vs, vs + vn, pos) - vs;
	nbrs[vi][di] = (nvi < vn && vs[nvi] == pos) ? nvi : -1;
      }

    for (int vi = 0; vi < vn; vi++)
      for (int r0 = 0; r0 < vn; r0++)
	for (int r1 = 0; r1 < vn; r1++)
	  for (int r2 = 0; r2 < vn; r2++) dists[vi][r0][r1][r2] = INF;
    dists[sv][rvs[0]][rvs[1]][rvs[2]] = 0;
    
    queue<Stat> q;
    q.push(Stat(sv, rvs));

    int min_dist = INF;
    ll gbits = (1LL << mvs[0]) | (1LL << mvs[1]) | (1LL << mvs[2]);
    
    while (! q.empty()) {
      Stat u = q.front(); q.pop();
      int ud = dists[u.vi][u.rs[0]][u.rs[1]][u.rs[2]];
      ll ubits = (1LL << u.rs[0]) | (1LL << u.rs[1]) | (1LL << u.rs[2]);
      
      if (ubits == gbits) {
	min_dist = ud;
	break;
      }
      
      for (int di = 0; di < 4; di++) {
	int vvi = nbrs[u.vi][di];
	if (vvi < 0) continue;

	Stat v(vvi, u.rs);
	bool ok = true;

	if (ubits & (1LL << vvi))
	  for (int ri = 0; ri < 3; ri++)
	    if (vvi == v.rs[ri]) {
	      int nrvi = nbrs[v.rs[ri]][di];
	      if (nrvi < 0 || (ubits & (1LL << nrvi))) ok = false;
	      v.rs[ri] = nrvi;
	      break;
	    }

	if (ok && dists[vvi][v.rs[0]][v.rs[1]][v.rs[2]] >= INF) {
	  dists[vvi][v.rs[0]][v.rs[1]][v.rs[2]] = ud + 1;
	  q.push(v);
	}
      }
    }

    cout << min_dist << endl;
  }

  return 0;
}
accuracy: 1
time_ms: 280
memory_kb: 27196
final_rank: 4

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define MAX 16

int H,W,gp[MAX*MAX];
char field[MAX][MAX];
const int dx[4] = {-1,0,1,0};
const int dy[4] = {0,-1,0,1};

struct State{
  int h,r[3];
};

inline bool check(const State &s){
  for(int i = 0 ; i < 3 ; i++){
    if(field[s.r[i]/W][s.r[i]%W] != '_'){
      return false;
    }
  }
  return true;
}

inline int canMove(const State &s,int &dir){
  if(field[s.h/W][s.h%W] == '#'){ return -1; }
  int idx = -1;
  for(int i = 0 ; i < 3 ; i++){
    if(s.h == s.r[i]){
      idx = i; break;
    }
  }
  if(idx == -1){ return 3; }
  int nx = s.h%W + dx[dir];
  int ny = s.h/W + dy[dir];
  if(field[ny][nx] == '#'){ return -1; }
  for(int i = 0 ; i < 3 ; i++){
    if(i == idx){ continue; }
    if(s.r[i]%W == nx && s.r[i]/W == ny){
      return -1;
    }
  }
  return idx;
}

bool visited[50][50][50][50];

int bfs(const State &S){
  queue<State> Q; Q.push(S);
  queue<int> step; step.push(0);
  const int dr[4] = {-1,-W,1,W};
  memset(visited,false,sizeof(visited));
  visited[gp[S.h]][gp[S.r[0]]][gp[S.r[1]]][gp[S.r[2]]] = true;

  while(!Q.empty()){
    State s = Q.front(); Q.pop();
    int st = step.front(); step.pop();
    if(check(s)){ return st; }
    for(int i = 0 ; i < 4 ; i++){
      s.h += dr[i];
      int r = canMove(s,i);
      if(r == -1){
        s.h -= dr[i];
        continue;
      }
      if(r == 3){
        if(!visited[gp[s.h]][gp[s.r[0]]][gp[s.r[1]]][gp[s.r[2]]]){
          visited[gp[s.h]][gp[s.r[0]]][gp[s.r[1]]][gp[s.r[2]]] = true;
          Q.push(s);
          step.push(st+1);
        }
      }else{
        s.r[r] += dr[i];
        if(!visited[gp[s.h]][gp[s.r[0]]][gp[s.r[1]]][gp[s.r[2]]]){
          visited[gp[s.h]][gp[s.r[0]]][gp[s.r[1]]][gp[s.r[2]]] = true;
          Q.push(s);
          step.push(st+1);
        }
        s.r[r] -= dr[i];
      }
      s.h -= dr[i];
    }
  }
  return -1;
}

int main(){
  while(cin >> W >> H,(W|H)){
    int r = 0,idx = 0;
    State start;
    for(int i = 0 ; i < H ; i++){
      for(int j = 0 ; j < W ; j++){
        cin >> field[i][j];
        if(field[i][j] == '@'){
          start.h = i*W+j;
        }else if(field[i][j] == '*'){
          start.r[r++] = i*W+j;
        }
        if(field[i][j] != '#'){
          gp[i*W+j] = idx++;
        }
      }
    }
    cout << bfs(start) << endl;
  }
  return 0;
}
accuracy: 1
time_ms: 320
memory_kb: 9232
final_rank: 1

code_snippet: #include<bits/stdc++.h>

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

using namespace std;

typedef pair<int,int> ii;

const int IINF = INT_MAX;

struct Data{
  ii hero,rock[3];
  int step;
  Data(ii hero=ii(0,0),ii r1=ii(0,0),ii r2=ii(0,0),ii r3=ii(0,0),int step=0):hero(hero),step(step){
    rock[0] = r1, rock[1] = r2, rock[2] = r3;
  }
  bool operator < ( const Data& data ) const {
    return step > data.step;
  }
};

int H,W,Index[20][20],mindist[60][60][60][60];
char G[20][20];
int dx[] = {0,1,0,-1};
int dy[] = {1,0,-1,0};

bool isValid(int x,int y){ return 0 <= x && x < W && 0 <= y && y < H; }

int main(){
  while( cin >> W >> H, W|H ){
    vector<ii> R,M;
    ii sp = ii(0,0);
    int dex = 0;
    rep(i,H) rep(j,W) {
      cin >> G[i][j];
      if( G[i][j] == '#' ) continue;
      Index[i][j] = dex++;
      if( G[i][j] == '@' ) sp = ii(j,i);
      else if( G[i][j] == '_' ) M.push_back(ii(j,i));
      else if( G[i][j] == '*' ) R.push_back(ii(j,i));
    }
    rep(i,dex) rep(j,dex) rep(k,dex) rep(l,dex) mindist[i][j][k][l] = IINF;
    sort(M.begin(),M.end());
    sort(R.begin(),R.end());
    int tmp_a = Index[sp.second][sp.first];
    int tmp_b = Index[R[0].second][R[0].first];
    int tmp_c = Index[R[1].second][R[1].first];
    int tmp_d = Index[R[2].second][R[2].first];
    mindist[tmp_a][tmp_b][tmp_c][tmp_d] = 0;
    priority_queue<Data> Q;
    Q.push(Data(sp,R[0],R[1],R[2],0));
    while( !Q.empty() ){
      Data data = Q.top(); Q.pop();
      tmp_a = Index[data.hero.second][data.hero.first];
      tmp_b = Index[data.rock[0].second][data.rock[0].first];
      tmp_c = Index[data.rock[1].second][data.rock[1].first];
      tmp_d = Index[data.rock[2].second][data.rock[2].first];
      if( mindist[tmp_a][tmp_b][tmp_c][tmp_d] < data.step ) continue;
      if( data.rock[0] == M[0] && data.rock[1] == M[1] && data.rock[2] == M[2] ) {
        cout << data.step << endl;
        break;
      }
      rep(i,4){
        Data tmp = data;
        tmp.hero.first += dx[i], tmp.hero.second += dy[i];
        if( G[tmp.hero.second][tmp.hero.first] == '#' ) continue;
        if( tmp.hero == tmp.rock[0] || tmp.hero == tmp.rock[1] || tmp.hero == tmp.rock[2] ) {
          if( tmp.hero == tmp.rock[0] ) tmp.rock[0].first += dx[i], tmp.rock[0].second += dy[i];
          if( tmp.hero == tmp.rock[1] ) tmp.rock[1].first += dx[i], tmp.rock[1].second += dy[i];
          if( tmp.hero == tmp.rock[2] ) tmp.rock[2].first += dx[i], tmp.rock[2].second += dy[i];
          if( G[tmp.rock[0].second][tmp.rock[0].first] == '#' ) continue;
          if( G[tmp.rock[1].second][tmp.rock[1].first] == '#' ) continue;
          if( G[tmp.rock[2].second][tmp.rock[2].first] == '#' ) continue;
          sort(tmp.rock,tmp.rock+3);
          int hi = Index[tmp.hero.second][tmp.hero.first];
          int r1i = Index[tmp.rock[0].second][tmp.rock[0].first];
          int r2i = Index[tmp.rock[1].second][tmp.rock[1].first];
          int r3i = Index[tmp.rock[2].second][tmp.rock[2].first];
          if( mindist[hi][r1i][r2i][r3i] > data.step + 1 ) {
            mindist[hi][r1i][r2i][r3i] = data.step + 1;
            Q.push(Data(tmp.hero,tmp.rock[0],tmp.rock[1],tmp.rock[2],data.step+1));
          }
        } else {
          int hi = Index[tmp.hero.second][tmp.hero.first];
          int r1i = Index[tmp.rock[0].second][tmp.rock[0].first];
          int r2i = Index[tmp.rock[1].second][tmp.rock[1].first];
          int r3i = Index[tmp.rock[2].second][tmp.rock[2].first];
          if( mindist[hi][r1i][r2i][r3i] > data.step + 1 ) {
            mindist[hi][r1i][r2i][r3i] = data.step + 1;
            Q.push(Data(tmp.hero,tmp.rock[0],tmp.rock[1],tmp.rock[2],data.step+1));
          }
        }

      }
    }

  }
  return 0;
}
accuracy: 1
time_ms: 580
memory_kb: 48460
final_rank: 10

code_snippet: #include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <algorithm>
#include <stack>
#include <queue>
#include <deque>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <cassert>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;
typedef long long ll;

const int    INF = 1000000000;
const int    MOD = 1000000007;
const double EPS = 1e-8;

inline bool valid(int x, int y, int W, int H){
    return x >= 0 && y >= 0 && x < W && y < H;
}

int encode(int x[4], int y[4]){
    int s = 0;
    for(int i = 0; i < 4; i++){
        s = (s << 8) | (x[i] << 4) | y[i];
    }
    return s;
}
void decode(int s, int x[4], int y[4]){
    for(int i = 3; i >= 0; i--){
        x[i] = (s >> 4) & 0xf;
        y[i] = s & 0xf;
        s >>= 8;
    }
}

int main(){
    int W, H;
    while(cin >> W >> H && W){
        char grid[30][30];
        REP(i, H) cin >> grid[i];
        int sx[4], sy[4];
        int rid = 1;
        REP(y, H) REP(x, W) if(grid[y][x] == '@'){ sx[0] = x, sy[0] = y; grid[y][x] = '.';
            REP(y, H) REP(x, W) if(grid[y][x] == '*'){ sx[rid] = x; sy[rid] = y; rid++; grid[y][x] = '.'; }
        }
        int start = encode(sx, sy);
        queue<int> que;
        map<int, int> dist;
        que.push(start);
        dist[start] = 0;
        while(!que.empty()){
            int s = que.front(); que.pop();
            int x[4], y[4];
            decode(s, x, y);
            bool goal = true;
            for(int i = 1; i < 4; i++) if(grid[y[i]][x[i]] != '_') goal = false;
            /*
            REP(i, 4) grid[y[i]][x[i]] = '1' + i;
            REP(y, H) cout << grid[y] << endl;
            cout << endl;
            REP(i, 4) grid[y[i]][x[i]] = '.';
            */
            if(goal){
                cout << dist[s] << endl;
                break;
            }
            const int dx[4] = {1, 0, -1, 0};
            const int dy[4] = {0, 1, 0, -1};
            REP(r, 4){
                int nx[4], ny[4];
                memcpy(nx, x, sizeof(x));
                memcpy(ny, y, sizeof(y));
                bool ok = true;
                for(int i = 0; i < 4; i++) if(nx[i] == nx[0] && ny[i] == ny[0]){ // i = 0 -> true
                    nx[i] += dx[r];
                    ny[i] += dy[r];
                    if(!valid(nx[i], ny[i], W, H) || grid[ny[i]][nx[i]] == '#') ok = false;
                }
                for(int i = 0; i < 4; i++) for(int j = i + 1; j < 4; j++) if(nx[i] == nx[j] && ny[i] == ny[j]) ok = false;
                int ns = encode(nx, ny);
                if(ok && !dist.count(ns)){
                    que.push(ns);
                    dist[ns] = dist[s] + 1;
                }
            }
        }
    }
    return 0;
}
accuracy: 1
time_ms: 5260
memory_kb: 60220
final_rank: 11

code_snippet: #include <iostream>
#include <cstdio>
#include <vector>
#include <list>
#include <cmath>
#include <fstream>
#include <algorithm>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <complex>
#include <iterator>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <stack>
#include <climits>
#include <deque>
#include <bitset>
#include <cassert>
#include <ctime>
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int dy[]={-1,0,1,0},dx[]={0,1,0,-1};
// adjust problem by problem
const double EPS=1e-8;
const double PI=acos(-1.0);
#ifdef __GNUC__
int popcount(int n){return __builtin_popcount(n);}
int popcount(ll n){return __builtin_popcountll(n);}
#endif
#ifndef __GNUC__
template<class T> int popcount(T n){int cnt=0;while(n){if(n%2)cnt++;n/=2;}return cnt;}
#endif
template<class T>int SIZE(T a){return a.size();}
template<class T>string IntToString(T num){string res;stringstream ss;ss<<num;return ss.str();}
template<class T>T StringToInt(string str){T res=0;for(int i=0;i<SIZE(str);i++)res=(res*10+str[i]-'0');return res;}
template<class T>T gcd(T a,T b){if(b==0)return a;return gcd(b,a%b);}
template<class T>T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> void PrintSeq(T &a,int sz){for(int i=0;i<sz;i++){cout<<a[i];if(sz==i+1)cout<<endl;else cout<<' ';}}
bool EQ(double a,double b){return abs(a-b)<EPS;}
void fastStream(){cin.tie(0);std::ios_base::sync_with_stdio(0);}
vector<string> split(string str,char del){
  vector<string> res;
  for(int i=0,s=0;i<SIZE(str);i++){
    if(str[i]==del){if(i-s!=0)res.push_back(str.substr(s,i-s));s=i+1;}
    else if(i==SIZE(str)-1){res.push_back(str.substr(s));}
  }
  return res;
}

int W,H;
char field[20][20];
int dists[51][51][51][51];

struct Sit{
  int self;
  int rocks[3];
  int ccost;
  Sit(){}
  Sit(int s,int r1,int r2,int r3,int c){
    self=s;
    rocks[0]=r1;
    rocks[1]=r2;
    rocks[2]=r3;
    ccost=c;
  }
};

void solve(){
  for(int i=0;i<H;i++)for(int j=0;j<W;j++)cin>>field[i][j];
  int posToIdx[20][20];
  vector<pii> idxToPos;
  vector<pii> rocks;
  set<int> goals;
  int idx=0;
  int sy,sx;
  for(int i=0;i<H;i++){
    for(int j=0;j<W;j++){
      if(field[i][j]!='#'){
        posToIdx[i][j]=idx++;
        idxToPos.push_back(pii(i,j));
      }
      else posToIdx[i][j]=-1;
      if(field[i][j]=='*'){
        rocks.push_back(pii(i,j));
        field[i][j]='.';
      }
      else if(field[i][j]=='_'){
        goals.insert(posToIdx[i][j]);
        field[i][j]='.';
      }
      else if(field[i][j]=='@'){
        sy=i;
        sx=j;
        field[i][j]='.';
      }
    }
  }
  queue<Sit> q;
  memset(dists,-1,sizeof(dists));
  q.push(Sit(posToIdx[sy][sx],posToIdx[rocks[0].first][rocks[0].second],posToIdx[rocks[1].first][rocks[1].second],posToIdx[rocks[2].first][rocks[2].second],0));
  dists[posToIdx[sy][sx]][posToIdx[rocks[0].first][rocks[0].second]][posToIdx[rocks[1].first][rocks[1].second]][posToIdx[rocks[2].first][rocks[2].second]]=0;
  while(q.size()){
    Sit sit=q.front();q.pop();
    int cy=idxToPos[sit.self].first;
    int cx=idxToPos[sit.self].second;
    // goal判定
    bool ok=true;
    for(int i=0;i<3;i++)
      if(!goals.count(sit.rocks[i]))ok=false;
    if(ok){
      cout<<sit.ccost<<endl;
      return;
    }
    char nowField[20][20];
    for(int i=0;i<4;i++){
      for(int i=0;i<H;i++)for(int j=0;j<W;j++)nowField[i][j]=field[i][j];
      for(int i=0;i<3;i++)nowField[idxToPos[sit.rocks[i]].first][idxToPos[sit.rocks[i]].second]='*';
      int ny=cy+dy[i];
      int nx=cx+dx[i];
      if(ny>=0&&nx>=0&&ny<H&&nx<W&&nowField[ny][nx]!='#'){
        int nSelfIdx=posToIdx[ny][nx];
        Sit nsit;
        nsit.self=nSelfIdx;
        if(nowField[ny][nx]=='.'){
          for(int j=0;j<3;j++)nsit.rocks[j]=sit.rocks[j];
          if(dists[nSelfIdx][nsit.rocks[0]][nsit.rocks[1]][nsit.rocks[2]]==-1){
            dists[nSelfIdx][nsit.rocks[0]][nsit.rocks[1]][nsit.rocks[2]]=sit.ccost+1;
            nsit.ccost=sit.ccost+1;
            q.push(nsit);
          }
        }
        else if(nowField[ny][nx]=='*'){
          int nny=ny+dy[i];
          int nnx=nx+dx[i];
          if(nowField[nny][nnx]!='.')continue;
          nowField[ny][nx]='.';
          nowField[nny][nnx]='*';
          int pos=0;
          for(int k=0;k<H;k++)
            for(int l=0;l<W;l++)
              if(nowField[k][l]=='*')
                nsit.rocks[pos++]=posToIdx[k][l];
          if(dists[nSelfIdx][nsit.rocks[0]][nsit.rocks[1]][nsit.rocks[2]]==-1){
            dists[nSelfIdx][nsit.rocks[0]][nsit.rocks[1]][nsit.rocks[2]]=sit.ccost+1;
            nsit.ccost=sit.ccost+1;
            q.push(nsit);
          }
        }
      }
    }
  }
}

int main(){

  while(cin>>W>>H&&(W|H))solve();
  
  return 0;
}
accuracy: 1
time_ms: 1220
memory_kb: 28568
final_rank: 6

code_snippet: #include <cstdio>
#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <bitset>
#include <numeric>
#include <climits>
#include <cfloat>
using namespace std;

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

unsigned toHash(int py, int px, vector<pair<int, int> >& rock)
{
    sort(rock.begin(), rock.end());

    unsigned ret = py * 16 + px;
    for(int i=0; i<3; ++i){
        ret *= 16 * 16;
        ret += rock[i].first * 16 + rock[i].second;
    }
    return ret;
}

void fromHash(unsigned hash, int& py, int& px, vector<pair<int, int> >& rock)
{
    rock.resize(3);

    for(int i=2; i>=0; --i){
        rock[i].second = hash % 16;
        hash /= 16;
        rock[i].first = hash % 16;
        hash /= 16;
    }

    px = hash % 16;
    py = hash / 16;
}

int main()
{
    for(;;){
        int h, w;
        cin >> w >> h;
        if(h == 0)
            return 0;

        int py, px;
        vector<pair<int, int> > start, goal;
        vector<string> grid(h, string(w, ' '));

        for(int i=0; i<h; ++i){
            for(int j=0; j<w; ++j){
                cin >> grid[i][j];
                if(grid[i][j] == '@'){
                    py = i;
                    px = j;
                }else if(grid[i][j] == '*'){
                    start.push_back(make_pair(i, j));
                }else if(grid[i][j] == '_'){
                    goal.push_back(make_pair(i, j));
                }
            }
        }
        sort(goal.begin(), goal.end());

        queue<unsigned> q;
        q.push(toHash(py, px, start));
        set<unsigned> history;
        history.insert(toHash(py, px, start));
        int ret = 0;

        for(;;){
            bool ok = false;
            int n = q.size();
            while(--n >= 0){
                int y0, x0;
                vector<pair<int, int> > rock0;
                fromHash(q.front(), y0, x0, rock0);
                q.pop();

                if(rock0 == goal){
                    cout << ret << endl;
                    ok = true;
                    break;
                }

                for(int i=0; i<4; ++i){
                    int y = y0 + dy[i];
                    int x = x0 + dx[i];
                    if(grid[y][x] == '#')
                        continue;

                    vector<pair<int, int> > rock = rock0;
                    vector<pair<int, int> >::iterator it = find(rock.begin(), rock.end(), make_pair(y, x));
                    if(it != rock.end()){
                        it->first  += dy[i];
                        it->second += dx[i];
                        if(grid[it->first][it->second] == '#' || count(rock.begin(), rock.end(), *it) > 1)
                            continue;
                    }

                    unsigned hash = toHash(y, x, rock);
                    if(history.find(hash) == history.end()){
                        q.push(hash);
                        history.insert(hash);
                    }
                }
            }

            if(ok)
                break;
            ++ ret;
        }
    }
}
accuracy: 1
time_ms: 2450
memory_kb: 20808
final_rank: 7

code_snippet: #include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <algorithm>
#include <numeric>
#include <functional>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <climits>
using namespace std;

typedef istringstream ISS;
typedef ostringstream OSS;
typedef vector<string> VS;
typedef char INT;
typedef vector<INT> VI;
typedef vector<VI> VVI;
typedef pair <INT, INT> II;
typedef vector <II> VII;

template<class T> ostream& operator << ( ostream& os, vector<T> v ) {
    for ( typename vector<T>::iterator it_i = v.begin(); it_i != v.end(); ++it_i ) {
        os << *it_i << ", ";
    }
    return os;
}


int W, H;
VS M;
map <II, int> ID;
int CID;

void setCellID( int r, int c ) {
    if ( ID.count( II( r, c ) ) ) return;
    ID[II(r,c)] = CID ++;
}

int getCellID( int r, int c ) {
    return ID[II(r,c)];
}

void init() {
    ID.clear();
    CID = 0;

    for ( int i = 0; i < H; ++ i ) {
        for ( int j = 0; j < W; ++ j ) {
            if ( M[i][j] == '#' ) continue;
            setCellID( i, j );
        }
    }
}

bool input() {
    if ( ! ( cin >> W >> H && W ) ) return false;
    M = VS(H);
    for ( int i = 0; i < H; ++ i ) {
        cin >> M[i];
    }
    return true;
}

typedef pair <II, int> STATE;
typedef pair <int, STATE> NODE; 
typedef queue <NODE> QUEUE;
typedef set <STATE> VISITED;
const int dr[4] = { 0, 0, 1, -1 };
const int dc[4] = { 1, -1, 0, 0 };
char rr[3];
char rc[3];
QUEUE Q;
bool V[51][51][51][51];

STATE getState( int r, int c ) {
    int bitState = 0;
    for ( int i = 0; i < 3; ++ i ) {
        bitState <<= 8;
        bitState |= ((rr[i]-1) << 4) | (rc[i]-1);
    }
    return STATE( II( r, c ), bitState );
}

II deployState( STATE state ) {
    for ( int i = 2; i >= 0; -- i ) {
        rr[i] = ( ( state.second & 0xF0 ) >> 4 ) + 1;
        rc[i] = ( state.second & 0x0F ) + 1;
        state.second >>= 8;
    }
    return state.first;
}

int solve() {
    Q = QUEUE();
    fill( (bool*)V, (bool*)V+51*51*51*51, false );
    char sr, sc;
    int rocks = 0, marks = 0;
    char rr_[3], rc_[3];
    char mr[3], mc[3];

    for ( int i = 0; i < H; ++ i ) {
        for ( int j = 0; j < W; ++ j ) {
            if ( M[i][j] == '@' ) {
                sr = i;
                sc = j;
                M[i][j] = '.';
            } else if ( M[i][j] == '*' ) {
                rr_[rocks] = i;
                rc_[rocks] = j;
                rocks ++;
                M[i][j] = '.';
            } else if ( M[i][j] == '_' ) {
                mr[marks] = i;
                mc[marks] = j;
                marks ++;
                M[i][j] = '.';
            }
        }
    }

    for ( int i = 0; i < 3; ++ i ) {
        rr[i] = rr_[i];
        rc[i] = rc_[i];
    }

    Q.push( NODE( 0, getState( sr, sc ) ) );
    V[getCellID(sr,sc)][getCellID(rr[0],rc[0])][getCellID(rr[1],rc[1])][getCellID(rr[2],rc[2])] = true;

    cin.ignore();
    cin.clear();

    while ( ! Q.empty() ) {
        NODE node = Q.front();
        Q.pop();

        int steps = node.first;
        STATE state = node.second;
        II ret = deployState( state );
        char r = ret.first;
        char c = ret.second;


        bool checked[3];
        fill( checked, checked+3, false );
        for ( int i = 0; i < 3; ++ i ) {
            for ( int j = 0; j < 3; ++ j ) {
                if ( rr[i] == mr[j] && rc[i] == mc[j] ) {
                    checked[j] = true;
                }
            }
        }
        if ( count( checked, checked+3, true ) == 3 ) {
            return steps;
        }

        for ( int i = 0; i < 4; ++ i ) {
            deployState( state );
            int nr = r + dr[i];
            int nc = c + dc[i];
            if ( nr < 0 || nr >= H || nc < 0 || nc >= W ) continue;
            bool flag = false; 
            for ( int j = 0; j < 3; ++ j ) {
                if ( nr == rr[j] && nc == rc[j] ) {
                    int nnr = nr + dr[i];
                    int nnc = nc + dc[i];
                    if ( nnr < 0 || nnr >= H || nnc < 0 || nnc >= W ) {
                        flag = true;
                        break;
                    }
                    if ( M[nnr][nnc] == '#' ) {
                        flag = true;
                        break;
                    }
                    for ( int k = 0; k < 3; ++ k ) {
                        if ( nnr == rr[k] && nnc == rc[k] ) {
                            flag = true;
                            break;
                        }
                    }
                    if ( flag ) break;
                    rr[j] = nnr;
                    rc[j] = nnc;
                    break;
                }
            }
            if ( flag ) continue;
            if ( M[nr][nc] == '#' ) continue;
            int nsteps = steps + 1;
            STATE state = getState( nr, nc );
            int a = getCellID(nr,nc);
            int b = getCellID(rr[0],rc[0]);
            int c = getCellID(rr[1],rc[1]);
            int d = getCellID(rr[2],rc[2]);
            if ( V[a][b][c][d] ) continue;
            V[a][b][c][d] = true;
            NODE next( nsteps, state );
            Q.push( next );
        }
    }
    
    return -1;
}

int main() {
    while ( input() ) {
        init();
        cout << solve() << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 1560
memory_kb: 8968
final_rank: 3

code_snippet: #include <iostream>
#include <queue>
#include <set>
#include <vector>
#include <utility>
#include <algorithm>
using namespace std;

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

typedef pair<int, int> Ps;
set<pair<Ps, int > > memo;
char f[17][17];

class State
{
public:
	vector<Ps> b;
	Ps p;
	int c;
	State(Ps p, int c, vector<Ps>& b)
	:p(p),c(c),b(b)
	{}
};

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

int main()
{
	int W,H;
	while(cin >> W >> H, (W||H))
	{
		memo.clear();
		
		Ps init;
		vector<Ps> bk;
		REP(i,H) REP(j,W) 
		{
			cin >> f[j][i];
			if(f[j][i]=='@') init=make_pair(j,i);
			if(f[j][i]=='*') bk.push_back(make_pair(j,i));
		}
		
		queue<State> q;
		q.push(State(init, 0, bk));
		
		while(!q.empty())
		{
			State s=q.front(); q.pop();
			bool ed=true;
			REP(i,s.b.size())
			{
				Ps p=s.b[i];
				if(f[p.first][p.second]!='_') ed=false;
			}
			
			if(ed)
			{
				cout << s.c << endl;
				break;
			}
			
			REP(i,4)
			{
				Ps p=s.p;
				int tx=p.first+dx[i], ty=p.second+dy[i];
				if(tx<0||ty<0||tx>=W||ty>=H) continue;
				if(f[tx][ty]=='#') continue;
				
				bool g=true;
				vector<Ps> tmp(3);
				REP(j,s.b.size())
				{
					Ps bp=s.b[j];
					if(bp.first==tx&&bp.second==ty)
					{
						int ttx=bp.first+dx[i], tty=bp.second+dy[i];
						if(ttx<0||tty<0||ttx>=W||tty>=H)
						{
							g=false;
							break;
						}
						if(f[ttx][tty]=='#')
						{
							g=false;
							break;
						}
						REP(k,s.b.size())
						{
							if(k==j) continue;
							if(s.b[k]==make_pair(ttx,tty))
							{
								g=false;
								break;
							}
						}
						
						if(g) tmp[j]=make_pair(ttx,tty);
						else break;
					}
					else tmp[j]=bp;
				}
				
				if(!g) continue;
				
				sort(tmp.begin(), tmp.end());
				int th=0;
				REP(k,tmp.size())
				{
					th<<=4;
					th|=(tmp[k].first-1);
					th<<=4;
					th|=(tmp[k].second-1);
				}
				Ps np=make_pair(tx,ty);
				if(memo.count(make_pair(np,th))) continue;
				
				memo.insert(make_pair(np,th));
				
				q.push(State(np, s.c+1, tmp));
			}
		}
	}
}
accuracy: 1
time_ms: 3730
memory_kb: 13000
final_rank: 8