#include #include #include #include using namespace std; typedef complex POS; const POS DIR[] = { POS(1, 0), POS(-1, 0), POS(0, 1), POS(0, -1) }; int TABLE[20][20]; POS GOAL; struct STATE{ POS man; POS cargo; int push; bool operator<(const STATE& rh)const{ if (push == rh.push){ if (man.real() == rh.man.real()){ if (man.imag() == rh.man.imag()){ if (cargo.real() == rh.cargo.real()){ return cargo.imag() < rh.cargo.imag(); } return cargo.real() < rh.cargo.real(); } return man.imag() < rh.man.imag(); } return man.real() < rh.man.real(); } return push < rh.push; } STATE() : push(0){} STATE(int state) : push(0){ cargo = POS(state & 0xf, (state & 0xf0) >> 4); man = POS((state & 0xf00) >> 8, (state & 0xf000) >> 12); push = ((state & 0x7fff0000) >> 16); } void Input(int w, int h){ for (int i = 0; i < 20; ++i){ for (int j = 0; j < 20; ++j){ TABLE[i][j] = 1; } } for (int y = 2; y <= h + 1; ++y){ for (int x = 2; x <= w + 1; ++x){ TABLE[x][y] = 0; int in; cin >> in; if (in == 1){ TABLE[x][y] = 1; } else if (in == 2){ cargo = POS(x, y); } else if (in == 3){ GOAL = POS(x, y); } else if (in == 4){ man = POS(x, y); } } } } bool IsGoal()const{ return GOAL == cargo; } int GetState()const{ int res = 0; res |= cargo.real(); res |= (cargo.imag() << 4); res |= (man.real() << 8); res |= (man.imag() << 12); return res; } bool CanGo(int dir){ POS pos1 = man + DIR[dir]; POS pos2 = man + DIR[dir] * 2; if (!TABLE[pos1.real()][pos1.imag()] && cargo != pos1){ return true; } if (cargo == pos1 && !TABLE[pos2.real()][pos2.imag()]){ return true; } return false; } void Go(int dir){ POS pos1 = man + DIR[dir]; POS pos2 = man + DIR[dir] * 2; if (cargo == pos1){ ++push; cargo = pos2; } man = pos1; } }; int Search(int w, int h) { unsigned int visited[0x10000]; memset(visited, 0xffffffff, sizeof(visited)); STATE init; init.Input(w, h); set open; open.insert(init); visited[init.GetState()] = 0; int res = INT_MAX; while (!open.empty()){ //cout << "Search : " << res << endl; set open2; for (set::iterator it = open.begin(); it != open.end(); ++it){ STATE s(*it); for (int dir = 0; dir < 4; ++dir){ if (!s.CanGo(dir)){ continue; } STATE next = s; next.Go(dir); if (next.push >= visited[next.GetState()]){ continue; } if (next.IsGoal()){ res = min(res, next.push); continue; } open2.insert(next); visited[next.GetState()] = next.push; } } swap(open, open2); } if (res == INT_MAX){ res = -1; } return res; } main() { int w, h; while (cin >> w >> h && !(w == 0 && h == 0)){ cout << Search(w, h) << endl; } }