Problem:
Problem E:
Manhattan Wiring
There is a rectangular area containing
n
×
m
cells. Two cells are marked with "2", and another two with "3". Some cells are occupied by obstacles. You should connect the two "2"s and also the two "3"s with non-intersecting lines. Lines can run only vertically or horizontally connecting
centers of cells without obstacles.
Lines cannot run on a cell with an obstacle. Only one line can run on a cell at most once. Hence,
a line cannot intersect with the other line, nor with itself. Under these constraints, the total
length of the two lines should be minimized. The length of a line is defined as the number of
cell borders it passes. In particular, a line connecting cells sharing their border has length 1.
Fig. 6(a) shows an example setting. Fig. 6(b) shows two lines satisfying the constraints above
with minimum total length 18.
Figure 6: An example setting and its solution
Input
The input consists of multiple datasets, each in the following format.
n m
row
1
...
       row
n
n
is the number of rows which satisfies 2 ≤
n
≤ 9.
m
is the number of columns which satisfies
2 ≤
m
≤ 9. Each row
i
is a sequence of
m
digits separated by a space. The digits mean the
following.
0
:   Empty
1
:   Occupied by an obstacle
2
:   Marked with "2"
3
:   Marked with "3"
The end of the input is indicated with a line containing two zeros separated by a space.
Output
For each dataset, one line containing the minimum total length of the two lines should be output.
If there is no pair of lines satisfying the requirement, answer "0" instead. No other characters
should be contained in the output.
Sample Input
5 5
0 0 0 0 0
0 0 0 3 0
2 0 2 0 0
1 0 1 1 1
0 0 0 0 3
2 3
2 2 0
0 3 3
6 5
2 0 0 0 0
0 3 0 0 0
0 0 0 0 0
1 1 1 0 0
0 0 0 0 0
0 0 2 3 0
5 9
0 0 0 0 0 0 0 0 0
0 0 0 0 3 0 0 0 0
0 2 0 0 0 0 0 2 0
0 0 0 0 3 0 0 0 0
0 0 0 0 0 0 0 0 0
9 9
3 0 0 0 0 0 0 0 2
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 3
9 9
0 0 0 1 0 0 0 0 0
0 2 0 1 0 0 0 0 3
0 0 0 1 0 0 0 0 2
0 0 0 1 0 0 0 0 3
0 0 0 1 1 1 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
9 9
0 0 0 0 0 0 0 0 0
0 3 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 2 3 2
0 0
Output for the Sample Input
18
2
17
12
0
52
43

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
typedef unsigned int T;
T n, m;
T ns[10][10];
bool vis[10][10][70000];
T ans[10][10][70000];
T san[] = {
	1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683, 59049
};

T f(T x, T y, T S) {
	if (x >= n) {
		if (S) return 100;
		return 0;
	}

	T &tmp = ans[x][y][S];
	if (vis[x][y][S]) return tmp;
	vis[x][y][S] = 1;

	if (y == m) {
		if (S / san[m]) return tmp = 100;
		return tmp = f(x + 1, 0, S * 3);
	}

	T a = S % san[y + 1] / san[y];
	T b = S % san[y + 2] / san[y + 1];

	switch (ns[x][y]) {
		case 2:
		case 3:
			if (a == ns[x][y] - 1 && b == 0) return tmp = f(x, y + 1, S - a * san[y]) + 1;
			if (a == 0 && b == ns[x][y] - 1) return tmp = f(x, y + 1, S - b * san[y + 1]) + 1;
			if (a == 0 && b == 0)
				return tmp = std::min(f(x, y + 1, S + (ns[x][y] - 1) * san[y]),
				                      f(x, y + 1, S + (ns[x][y] - 1) * san[y + 1])) + 1;
			return tmp = 100;
		case 1:
			if (a || b) return tmp = 100;
			return tmp = f(x, y + 1, S);
		case 0:
			if (a && b && a == b)
				return tmp = f(x, y + 1, S - a * san[y] - b * san[y + 1]) + 1;
			if (bool(a)^bool(b))
				return tmp = std::min(f(x, y + 1, S - a * san[y] - b * san[y + 1] + a * san[y] + b * san[y]),
				                      f(x, y + 1, S - a * san[y] - b * san[y + 1] + a * san[y + 1] + b * san[y + 1])) + 1;
			if (a == 0 && b == 0)
				return tmp = std::min(std::min(f(x, y + 1, S + 2 * san[y] + 2 * san[y + 1]),
				                               f(x, y + 1, S + 1 * san[y] + 1 * san[y + 1])) + 1,
				                      f(x, y + 1, S));
			return tmp = 100;
		default:
			exit(-1);
	}
}

int main() {
	while (scanf("%u%u", &n, &m) && !(n == m && n == 0)) {
		memset(vis, 0, sizeof vis);
		for (T i = 0; i < n; ++i)
			for (T j = 0; j < m; ++j)
				scanf("%u", &ns[i][j]);

		printf("%u\n", f(0, 0, 0) >= 100 ? 0 : (f(0, 0, 0) - 2));
	}
}
accuracy: 1
time_ms: 90
memory_kb: 33384
final_rank: 12

code_snippet: // 2006 Yokohama: Manhattan Wiring
// POJ 3133
// ACM-ICPC Live Archive 3620
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 9
const int INF = 1 << 20;
const int MAX_STATE = 59049 + 1;
int n, m, g[N][N];
int best[N][N][MAX_STATE];

struct STATE {
	int up[N], left;
	STATE() : left(0) {}

	// Encode the status to a integer. It's used in querying the best array.
	int encode() {
		int code = left;
		for (int i = 0; i < m; i++)
			code = code * 3 + up[i];
		return code;
	}

	// Determine whether the next status is legal. If legal, then generate the new status.
	bool generateNext(int row, int col, int up, int down, int left, int right, STATE &newState) {
		// It's illegal to exceed the boundary.
		if (col == 0 && left || row == 0 && up || col == m - 1 && right || row == n - 1 && down)
			return false;
		// The plug-ins must match
		if (left != this->left || up != this->up[col])
			return false;

		// The only changed plug-in is the left one and up[col] one.
		for (int i = 0; i < m; i++)
			newState.up[i] = this->up[i];
		newState.up[col] = down;
		newState.left = right;
		return true;
	}
};

int calc(int x, int y, STATE &state) {
	if (y == m)
		x++, y = 0;
	if (x == n)
		return 0;

	int key = state.encode();
	if (best[x][y][key] != -1)
		return best[x][y][key];

	STATE newState;
	int ans = INF;

	if (g[x][y] == 0) {
		// Empty cell, we can try all combination : no plug-in or plug-ins with two ends.
		if (state.generateNext(x, y, 0, 0, 0, 0, newState))
			ans = min(ans, calc(x, y + 1, newState));
		for (int t = 1; t < 3; t++) {
			if (state.generateNext(x, y, 0, 0, t, t, newState))
				ans = min(ans, calc(x, y + 1, newState) + 2);
			if (state.generateNext(x, y, t, t, 0, 0, newState))
				ans = min(ans, calc(x, y + 1, newState) + 2);
			if (state.generateNext(x, y, t, 0, t, 0, newState))
				ans = min(ans, calc(x, y + 1, newState) + 2);
			if (state.generateNext(x, y, t, 0, 0, t, newState))
				ans = min(ans, calc(x, y + 1, newState) + 2);
			if (state.generateNext(x, y, 0, t, 0, t, newState))
				ans = min(ans, calc(x, y + 1, newState) + 2);
			if (state.generateNext(x, y, 0, t, t, 0, newState))
				ans = min(ans, calc(x, y + 1, newState) + 2);
		}
	} else if (g[x][y] == 1) {
		if (state.generateNext(x, y, 0, 0, 0, 0, newState))
			ans = min(ans, calc(x, y + 1, newState));
	} else if (g[x][y] >= 2) {
		// The cell which is the endpoint of the polyline. We can only try the plug-ins with one end
		if (state.generateNext(x, y, g[x][y] - 1, 0, 0, 0, newState))
			ans = min(ans, calc(x, y + 1, newState) + 1);
		if (state.generateNext(x, y, 0, g[x][y] - 1, 0, 0, newState))
			ans = min(ans, calc(x, y + 1, newState) + 1);
		if (state.generateNext(x, y, 0, 0, g[x][y] - 1, 0, newState))
			ans = min(ans, calc(x, y + 1, newState) + 1);
		if (state.generateNext(x, y, 0, 0, 0, g[x][y] - 1, newState))
			ans = min(ans, calc(x, y + 1, newState) + 1);
	}
	return best[x][y][key] = ans;
}

int main() {
	while (scanf("%d%d", &n, &m) && n) {
		for (int i = 0; i < n; i++)
			for (int j = 0; j < m; j++)
				scanf("%d", &g[i][j]);

		STATE s;
		memset(best, -1, sizeof(best));
		memset(s.up, 0, sizeof(s.up));
		int ans = calc(0, 0, s);
		if (ans == INF)
			ans = 0;
		printf("%d\n", ans / 2);

	}
	return 0;
}
accuracy: 1
time_ms: 240
memory_kb: 21320
final_rank: 9

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;

const int IINF = INT_MAX;
const int MAX_W = 9;
typedef pair<int,int> ii;


int h,w;
int field[10][10],indice[10][10];
int dp[2][1<<((MAX_W+1)*2)];
int dx[] = {1,0,-1,0};
int dy[] = {0,1,0,-1};

inline bool isValid(int x,int y) { return 0 <= x && x < w && 0 <= y && y < h; }

#define SET(bitmask,index,value) ( bitmask = ( ( bitmask & ~(1<<(2*index)) & ~(1<<(2*index+1)) ) | ( value << (index*2) ) ) )
#define GET(bitmask,x) ( ( ( bitmask >> ( 2 * x ) ) & 1 ) | ( ( ( bitmask >> (2*x+1) ) & 1) << 1 ) )
#define FIX(bitmask) ((bitmask<<2)&((1<<(2*(w+1)))-1))
#define STAR ( field[y][x] == 2 || field[y][x] == 3 )
#define update(x,v) ( ( x == -1 ) ? ( x = v ) : ( x = min(x,v) ) )


void compute(){

  vector<int> state;
  rep(bitmask,(1<<((w+1)*2))) {
    bool success = true;
    for(int i=0;i<(w+1)*2;i+=2) if( ( ( bitmask >> i ) & 1 ) && ( ( bitmask >> (i+1) ) & 1 ) ) { success = false; break; }
    if( success ) state.push_back(bitmask);
  }
  memset(dp,-1,sizeof(dp));

  int _size = state.size();
  bool initter = true, phase = false;
  int mini = IINF;
  int encounter = 0;
  rep(y,h){
    rep(x,w){

      if( field[y][x] == 2 || field[y][x] == 3 ) ++encounter;
      if( initter ) dp[phase][0] = 0;

      rep(i,_size){
        int bitmask = state[i];

        if( dp[phase][bitmask] == -1 ) continue;
        if( dp[phase][bitmask] >= mini ) continue;

        // ?????????
        if( field[y][x] == 1 ) {
          int nbitmask = bitmask;
          SET(nbitmask,x,0);
          if( x == w-1 ) nbitmask = FIX(nbitmask);
          update(dp[!phase][nbitmask],dp[phase][bitmask]);
          continue;
        }

        int nbitmask;
        // 0 0
        if( !( ( GET(bitmask,x) == 0 ) && ( GET(bitmask,(x+1)) == 0 ) ) ) goto Label1;
        if( STAR ) {
          // x 0
          if( y+1 < h && field[y+1][x] != 1 ) {
            nbitmask = bitmask;
            SET(nbitmask,x,((field[y][x]==3)+1));
            if( x == w-1 ) nbitmask = FIX(nbitmask);
          
            update(dp[!phase][nbitmask],dp[phase][bitmask]+1);
          }
          // 0 x
          if( x+1 < w && field[y][x+1] != 1 ) {
            nbitmask = bitmask;
            SET(nbitmask,(x+1),((field[y][x]==3)+1));

            if( x == w-1 ) nbitmask = FIX(nbitmask);

            update(dp[!phase][nbitmask],dp[phase][bitmask]+1);
          }
        } else {
          // x x
          if( x+1 < w && y+1 < h && field[y][x+1] != 1 && field[y+1][x] != 1 ) {
            REP(color,1,3){
              nbitmask = bitmask;
              SET(nbitmask,x,color);
              SET(nbitmask,(x+1),color);
              if( x == w-1 ) nbitmask = FIX(nbitmask);
              update(dp[!phase][nbitmask],(dp[phase][bitmask]+1));
            }
          }
          // 0 0
          nbitmask = bitmask;
          SET(nbitmask,x,0);
          SET(nbitmask,(x+1),0);
          if( x == w-1 ) nbitmask = FIX(nbitmask);
          update(dp[!phase][nbitmask],dp[phase][bitmask]);
        }

        continue;
      Label1:;
        // x 0
        // 0 x
        int color;
        if( !( ( GET(bitmask,x) && ( GET(bitmask,(x+1)) == 0 ) ) || ( GET(bitmask,(x+1)) && ( GET(bitmask,x) == 0 ) ) ) ) goto Label2;
        color = GET(bitmask,x) | GET(bitmask,(x+1));
        if( STAR ) {
          // 0 0
          if( ((color==1)?2:3) == field[y][x] ) {
            nbitmask = bitmask;
            SET(nbitmask,x,0);
            SET(nbitmask,(x+1),0);
            if( x == w-1 ) nbitmask = FIX(nbitmask);
            update(dp[!phase][nbitmask],dp[phase][bitmask]+1);
          }
        } else {
          // x 0
          if( y+1 < h && field[y+1][x] != 1 ) {
            nbitmask = bitmask;
            SET(nbitmask,x,color);
            SET(nbitmask,(x+1),0);
            if( x == w-1 ) nbitmask = FIX(nbitmask);


            update(dp[!phase][nbitmask],(dp[phase][bitmask]+1));
          }
          
          // 0 x
          if( x+1 < w && field[y][x+1] != 1 ) {
            nbitmask = bitmask;
            SET(nbitmask,x,0);
            SET(nbitmask,(x+1),color);

            if( x == w-1 ) nbitmask = FIX(nbitmask);
            update(dp[!phase][nbitmask],(dp[phase][bitmask]+1));
          }
        }
        continue;
      Label2:;
        // x x
        if( !( GET(bitmask,x) && GET(bitmask,(x+1)) ) ) goto Label3;
        if( GET(bitmask,x) != GET(bitmask,(x+1)) ) goto Label3;

        color = GET(bitmask,x);
        
        // 0 0
        if( !STAR ) {
          nbitmask = bitmask;
          SET(nbitmask,x,0);
          SET(nbitmask,(x+1),0);
          if( x == w-1 ) nbitmask = FIX(nbitmask);
          update(dp[!phase][nbitmask],dp[phase][bitmask]+1);
        }
      Label3:;

      }
      if( field[y][x] == 2 || field[y][x] == 3 ) initter = false;
      rep(i,_size) dp[phase][state[i]] = -1;
      if( encounter >= 4 && dp[!phase][0] != -1 ) {
        mini = min(mini,dp[!phase][0]);
      }
      phase = !phase;
    }
  }
  if( dp[phase][0] != -1 ) mini = min(mini,dp[phase][0]);
  if( mini != IINF ) printf("%d\n",mini-2);
  else puts("0");
}

int main(){
  while( scanf("%d %d",&h,&w), h|w ){
    rep(i,h) rep(j,w) scanf("%d",&field[i][j]);
    compute();
  }
  return 0;
}
accuracy: 1
time_ms: 410
memory_kb: 9780
final_rank: 4

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;

const int IINF = INT_MAX;
const int MAX_W = 9;
typedef pair<int,int> ii;


int h,w;
int field[10][10],indice[10][10];
int dp[2][1<<((MAX_W+1)*2)];
int dx[] = {1,0,-1,0};
int dy[] = {0,1,0,-1};

inline bool isValid(int x,int y) { return 0 <= x && x < w && 0 <= y && y < h; }

#define SET(bitmask,index,value) ( bitmask = ( ( bitmask & ~(1<<(2*index)) & ~(1<<(2*index+1)) ) | ( value << (index*2) ) ) )
#define GET(bitmask,x) ( ( ( bitmask >> ( 2 * x ) ) & 1 ) | ( ( ( bitmask >> (2*x+1) ) & 1) << 1 ) )
#define FIX(bitmask) ((bitmask<<2)&((1<<(2*(w+1)))-1))
#define STAR ( field[y][x] == 2 || field[y][x] == 3 )
#define update(x,v) ( ( x == -1 ) ? ( x = v ) : ( x = min(x,v) ) )


void compute(){

  vector<int> state;
  rep(bitmask,(1<<((w+1)*2))) {
    bool success = true;
    for(int i=0;i<(w+1)*2;i+=2) if( ( ( bitmask >> i ) & 1 ) && ( ( bitmask >> (i+1) ) & 1 ) ) { success = false; break; }
    if( success ) state.push_back(bitmask);
  }
  memset(dp,-1,sizeof(dp));

  int _size = state.size();
  bool initter = true, phase = false;
  int mini = IINF;
  int encounter = 0;
  rep(y,h){
    rep(x,w){

      if( field[y][x] == 2 || field[y][x] == 3 ) ++encounter;
      if( initter ) dp[phase][0] = 0;

      rep(i,_size){
        int bitmask = state[i];

        if( dp[phase][bitmask] == -1 ) continue;

        // ?????????
        if( field[y][x] == 1 ) {
          int nbitmask = bitmask;
          SET(nbitmask,x,0);
          if( x == w-1 ) nbitmask = FIX(nbitmask);
          update(dp[!phase][nbitmask],dp[phase][bitmask]);
          continue;
        }

        int nbitmask;
        // 0 0
        if( !( ( GET(bitmask,x) == 0 ) && ( GET(bitmask,(x+1)) == 0 ) ) ) goto Label1;
        if( STAR ) {
          // x 0
          if( y+1 < h && field[y+1][x] != 1 ) {
            nbitmask = bitmask;
            SET(nbitmask,x,((field[y][x]==3)+1));
            if( x == w-1 ) nbitmask = FIX(nbitmask);
          
            update(dp[!phase][nbitmask],dp[phase][bitmask]+1);
          }
          // 0 x
          if( x+1 < w && field[y][x+1] != 1 ) {
            nbitmask = bitmask;
            SET(nbitmask,(x+1),((field[y][x]==3)+1));

            if( x == w-1 ) nbitmask = FIX(nbitmask);

            update(dp[!phase][nbitmask],dp[phase][bitmask]+1);
          }
        } else {
          // x x
          if( x+1 < w && y+1 < h && field[y][x+1] != 1 && field[y+1][x] != 1 ) {
            REP(color,1,3){
              nbitmask = bitmask;
              SET(nbitmask,x,color);
              SET(nbitmask,(x+1),color);
              if( x == w-1 ) nbitmask = FIX(nbitmask);
              update(dp[!phase][nbitmask],(dp[phase][bitmask]+1));
            }
          }
          // 0 0
          nbitmask = bitmask;
          SET(nbitmask,x,0);
          SET(nbitmask,(x+1),0);
          if( x == w-1 ) nbitmask = FIX(nbitmask);
          update(dp[!phase][nbitmask],dp[phase][bitmask]);
        }

        continue;
      Label1:;
        // x 0
        // 0 x
        int color;
        if( !( ( GET(bitmask,x) && ( GET(bitmask,(x+1)) == 0 ) ) || ( GET(bitmask,(x+1)) && ( GET(bitmask,x) == 0 ) ) ) ) goto Label2;
        color = GET(bitmask,x) | GET(bitmask,(x+1));
        if( STAR ) {
          // 0 0
          if( ((color==1)?2:3) == field[y][x] ) {
            nbitmask = bitmask;
            SET(nbitmask,x,0);
            SET(nbitmask,(x+1),0);
            if( x == w-1 ) nbitmask = FIX(nbitmask);
            update(dp[!phase][nbitmask],dp[phase][bitmask]+1);
          }
        } else {
          // x 0
          if( y+1 < h && field[y+1][x] != 1 ) {
            nbitmask = bitmask;
            SET(nbitmask,x,color);
            SET(nbitmask,(x+1),0);
            if( x == w-1 ) nbitmask = FIX(nbitmask);


            update(dp[!phase][nbitmask],(dp[phase][bitmask]+1));
          }
          
          // 0 x
          if( x+1 < w && field[y][x+1] != 1 ) {
            nbitmask = bitmask;
            SET(nbitmask,x,0);
            SET(nbitmask,(x+1),color);

            if( x == w-1 ) nbitmask = FIX(nbitmask);
            update(dp[!phase][nbitmask],(dp[phase][bitmask]+1));
          }
        }
        continue;
      Label2:;
        // x x
        if( !( GET(bitmask,x) && GET(bitmask,(x+1)) ) ) goto Label3;
        if( GET(bitmask,x) != GET(bitmask,(x+1)) ) goto Label3;

        color = GET(bitmask,x);
        
        // 0 0
        if( !STAR ) {
          nbitmask = bitmask;
          SET(nbitmask,x,0);
          SET(nbitmask,(x+1),0);
          if( x == w-1 ) nbitmask = FIX(nbitmask);
          update(dp[!phase][nbitmask],dp[phase][bitmask]+1);
        }
      Label3:;

      }
      if( field[y][x] == 2 || field[y][x] == 3 ) initter = false;
      rep(i,_size) dp[phase][state[i]] = -1;
      if( encounter >= 4 && dp[!phase][0] != -1 ) {
        mini = min(mini,dp[!phase][0]);
      }
      phase = !phase;
    }
  }
  if( dp[phase][0] != -1 ) mini = min(mini,dp[phase][0]);
  if( mini != IINF ) printf("%d\n",mini-2);
  else puts("0");
}

int main(){
  while( scanf("%d %d",&h,&w), h|w ){
    rep(i,h) rep(j,w) scanf("%d",&field[i][j]);
    compute();
  }
  return 0;
}
accuracy: 1
time_ms: 420
memory_kb: 9780
final_rank: 5

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;

const int IINF = INT_MAX;
const int MAX_W = 9;
typedef pair<int,int> ii;


int h,w;
int field[10][10],indice[10][10];
int dp[2][1<<((MAX_W+1)*2)];
int dx[] = {1,0,-1,0};
int dy[] = {0,1,0,-1};

inline bool isValid(int x,int y) { return 0 <= x && x < w && 0 <= y && y < h; }

#define SET(bitmask,index,value) ( bitmask = ( ( bitmask & ~(1<<(2*index)) & ~(1<<(2*index+1)) ) | ( value << (index*2) ) ) )
#define GET(bitmask,x) ( ( ( bitmask >> ( 2 * x ) ) & 1 ) | ( ( ( bitmask >> (2*x+1) ) & 1) << 1 ) )
#define FIX(bitmask) ((bitmask<<2)&((1<<(2*(w+1)))-1))
#define STAR ( field[y][x] == 2 || field[y][x] == 3 )
#define update(x,v) ( ( x == -1 ) ? ( x = v ) : ( x = min(x,v) ) )


void compute(){

  set<int> S;
  vector<int> state;
  rep(bitmask,(1<<((w+1)*2))) {
    bool success = true;
    for(int i=0;i<(w+1)*2;i+=2){
      if( ( ( bitmask >> i ) & 1 ) && ( ( bitmask >> (i+1) ) & 1 ) ) { success = false; break; }
    }
    if( success ) state.push_back(bitmask), S.insert(bitmask);
  }
  memset(dp,-1,sizeof(dp));

  int _size = state.size();
  bool initter = true, phase = false;
  int mini = IINF;
  int encounter = 0;
  rep(y,h){
    rep(x,w){
      /*
      cout << x << "," << y << endl;
      rep(i,_size){
        if( dp[phase][state[i]] != -1 ) {
          bitset<12> BIT(state[i]);
          for(int j=0;j<12;j+=2){
            cout << BIT[j] << BIT[j+1] << " ";
          } 
          cout << " = " << dp[phase][state[i]] << endl;
        }
      }
      */
      if( field[y][x] == 2 || field[y][x] == 3 ) ++encounter;
      if( initter ) dp[phase][0] = 0;

      rep(i,_size){
        int bitmask = state[i];

        if( dp[phase][bitmask] == -1 ) continue;
        bitset<12> bit(bitmask);


        assert( S.count(bitmask));
        // ?????????
        if( field[y][x] == 1 ) {
          int nbitmask = bitmask;
          SET(nbitmask,x,0);
          if( x == w-1 ) nbitmask = FIX(nbitmask);
          update(dp[!phase][nbitmask],dp[phase][bitmask]);
          continue;
        }

        int nbitmask;
        // 0 0
        if( !( ( GET(bitmask,x) == 0 ) && ( GET(bitmask,(x+1)) == 0 ) ) ) goto Label1;
        if( STAR ) {
          // x 0
          if( y+1 < h && field[y+1][x] != 1 ) {
            nbitmask = bitmask;
            SET(nbitmask,x,((field[y][x]==3)+1));
          if( x == w-1 ) nbitmask = FIX(nbitmask);

            update(dp[!phase][nbitmask],dp[phase][bitmask]+1);
          }
          // 0 x
          if( x+1 < w && field[y][x+1] != 1 ) {
            nbitmask = bitmask;
            SET(nbitmask,(x+1),((field[y][x]==3)+1));

          if( x == w-1 ) nbitmask = FIX(nbitmask);

          update(dp[!phase][nbitmask],dp[phase][bitmask]+1);
          }
        } else {
          // x x
          if( x+1 < w && y+1 < h && field[y][x+1] != 1 && field[y+1][x] != 1 ) {
            REP(color,1,3){
              nbitmask = bitmask;
              SET(nbitmask,x,color);
              SET(nbitmask,(x+1),color);
              if( x == w-1 ) nbitmask = FIX(nbitmask);
              update(dp[!phase][nbitmask],(dp[phase][bitmask]+1));
            }
          }
          // 0 0
          nbitmask = bitmask;
          SET(nbitmask,x,0);
          SET(nbitmask,(x+1),0);
          if( x == w-1 ) nbitmask = FIX(nbitmask);
          update(dp[!phase][nbitmask],dp[phase][bitmask]);
        }

        continue;
      Label1:;
        // x 0
        // 0 x
        int color;
        if( !( ( GET(bitmask,x) && ( GET(bitmask,(x+1)) == 0 ) ) || ( GET(bitmask,(x+1)) && ( GET(bitmask,x) == 0 ) ) ) ) goto Label2;
        color = GET(bitmask,x) | GET(bitmask,(x+1));
        assert( color == 1 || color == 2 );
        if( STAR ) {
          // 0 0
          if( ((color==1)?2:3) == field[y][x] ) {

            nbitmask = bitmask;
            SET(nbitmask,x,0);
            SET(nbitmask,(x+1),0);
          if( x == w-1 ) nbitmask = FIX(nbitmask);
            update(dp[!phase][nbitmask],dp[phase][bitmask]+1);
          }
        } else {
          // x 0
          if( y+1 < h && field[y+1][x] != 1 ) {
            nbitmask = bitmask;
            SET(nbitmask,x,color);
            SET(nbitmask,(x+1),0);
          if( x == w-1 ) nbitmask = FIX(nbitmask);


            update(dp[!phase][nbitmask],(dp[phase][bitmask]+1));
          }
          
          // 0 x
          if( x+1 < w && field[y][x+1] != 1 ) {
            nbitmask = bitmask;
            SET(nbitmask,x,0);
            SET(nbitmask,(x+1),color);

          if( x == w-1 ) nbitmask = FIX(nbitmask);
            update(dp[!phase][nbitmask],(dp[phase][bitmask]+1));
          }
        }
        continue;
      Label2:;
        // x x
        if( !( GET(bitmask,x) && GET(bitmask,(x+1)) ) ) goto Label3;
        if( GET(bitmask,x) != GET(bitmask,(x+1)) ) goto Label3;

        color = GET(bitmask,x);
        assert( color );
        //assert( GET(bitmask,x) == GET(bitmask,(x+1)) );
        
        // 0 0
        if( !STAR ) {
          nbitmask = bitmask;
          SET(nbitmask,x,0);
          SET(nbitmask,(x+1),0);
          if( x == w-1 ) nbitmask = FIX(nbitmask);
          update(dp[!phase][nbitmask],dp[phase][bitmask]+1);
        }
      Label3:;

      }
      if( field[y][x] == 2 || field[y][x] == 3 ) initter = false;
      rep(i,_size) dp[phase][state[i]] = -1;
      if( encounter >= 4 && dp[!phase][0] != -1 ) {
        mini = min(mini,dp[!phase][0]);
      }
      phase = !phase;
    }
  }

  /*
  puts("final");
  rep(i,_size){
    if( dp[phase][state[i]] != -1 ) {
      bitset<12> BIT(state[i]);
      for(int j=0;j<12;j+=2){
        cout << BIT[j] << BIT[j+1] << " ";
      } 
      cout << " = " << dp[phase][state[i]] << endl;
    }
  }
  */
  if( dp[phase][0] != -1 ) mini = min(mini,dp[phase][0]);
  if( mini != IINF ) printf("%d\n",mini-2);
  else puts("0");
}

int main(){


  while( scanf("%d %d",&h,&w), h|w ){
    rep(i,h) rep(j,w) scanf("%d",&field[i][j]);
    compute();
  }
  return 0;
}
accuracy: 1
time_ms: 920
memory_kb: 12164
final_rank: 8

code_snippet: #include<cstdio>
#include<cstring>

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

using namespace std;

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

int h,w,B[9][9];

int x2,y2,x3,y3; // 2, 3 それぞれの出発点

int bfs(int x,int y,int tar){
	int d[9][9];
	memset(d,-1,sizeof d);
	d[y][x]=0;
	int Q[81],head=0,tail=0; Q[tail++]=y*w+x;
	while(head<tail){
		int i=Q[head]/w,j=Q[head]%w; head++;
		rep(k,4){
			int yy=i+dy[k],xx=j+dx[k];
			if(0<=yy && yy<h && 0<=xx && xx<w && d[yy][xx]==-1){
				if(B[yy][xx]==tar) return d[i][j]+1;
				if(B[yy][xx]== 0 ) Q[tail++]=yy*w+xx, d[yy][xx]=d[i][j]+1;
			}
		}
	}
	return 777;
}

int ans;
void dfs(int x,int y,int now){
	int hstar=bfs(x,y,2)+bfs(x3,y3,3);
	if(ans<now+1+hstar) return;

	// これまでのパスと接したら枝刈り
	int cnt=0;
	rep(k,4){
		int xx=x+dx[k],yy=y+dy[k];
		if(0<=xx && xx<w && 0<=yy && yy<h && B[yy][xx]==7) cnt++;
	}
	if(cnt>=2) return;

	// 777...777
	// 700...007
	// ?00...00?
	// というパターン ( or 回転/反転して一致するもの ) があれば枝刈り
	for(int L=3;L<=8;L++){
		bool ng;
		if(y>0 && x+L-1<w){
			ng=true;
			if(ng) rep(j,L) if(B[y-1][x+j]!=7) { ng=false; break; }
			if(ng) rep(j,L) if(B[y  ][x+j]!=(j==0||j==L-1?7:0)) { ng=false; break; }
			if(ng && L>=5 && y+1<h) rep(j,L) if(0<j && j<L-1 && B[y+1][x+j]!=0) { ng=false; break; }
			if(ng) return;
		}
		if(y+1<h && x+L-1<w){
			ng=true;
			if(ng && L>=5 && y>0) rep(j,L) if(0<j && j<L-1 && B[y-1][x+j]!=0) { ng=false; break; }
			if(ng) rep(j,L) if(B[y  ][x+j]!=(j==0||j==L-1?7:0)) { ng=false; break; }
			if(ng) rep(j,L) if(B[y+1][x+j]!=7) { ng=false; break; }
			if(ng) return;
		}
		if(y>0 && x-L+1>=0){
			ng=true;
			if(ng) rep(j,L) if(B[y-1][x-j]!=7) { ng=false; break; }
			if(ng) rep(j,L) if(B[y  ][x-j]!=(j==0||j==L-1?7:0)) { ng=false; break; }
			if(ng && L>=5 && y+1<h) rep(j,L) if(0<j && j<L-1 && B[y+1][x-j]!=0) { ng=false; break; }
			if(ng) return;
		}
		if(y+1<h && x-L+1>=0){
			ng=true;
			if(ng && L>=5 && y>0) rep(j,L) if(0<j && j<L-1 && B[y-1][x-j]!=0) { ng=false; break; }
			if(ng) rep(j,L) if(B[y  ][x-j]!=(j==0||j==L-1?7:0)) { ng=false; break; }
			if(ng) rep(j,L) if(B[y+1][x-j]!=7) { ng=false; break; }
			if(ng) return;
		}
		if(y+L-1<h && x>0){
			ng=true;
			if(ng) rep(i,L) if(B[y+i][x-1]!=7) { ng=false; break; }
			if(ng) rep(i,L) if(B[y+i][x  ]!=(i==0||i==L-1?7:0)) { ng=false; break; }
			if(ng && L>=5 && x+1<w) rep(i,L) if(0<i && i<L-1 && B[y+i][x+1]!=0) { ng=false; break; }
			if(ng) return;
		}
		if(y+L-1<h && x+1<w){
			ng=true;
			if(ng && L>=5 && x>0) rep(i,L) if(0<i && i<L-1 && B[y+i][x-1]!=0) { ng=false; break; }
			if(ng) rep(i,L) if(B[y+i][x  ]!=(i==0||i==L-1?7:0)) { ng=false; break; }
			if(ng) rep(i,L) if(B[y+i][x+1]!=7) { ng=false; break; }
			if(ng) return;
		}
		if(y-L+1>=0 && x>0){
			ng=true;
			if(ng) rep(i,L) if(B[y-i][x-1]!=7) { ng=false; break; }
			if(ng) rep(i,L) if(B[y-i][x  ]!=(i==0||i==L-1?7:0)) { ng=false; break; }
			if(ng && L>=5 && x+1<w) rep(i,L) if(0<i && i<L-1 && B[y-i][x+1]!=0) { ng=false; break; }
			if(ng) return;
		}
		if(y-L+1>=0 && x+1<w){
			ng=true;
			if(ng && L>=5 && x>0) rep(i,L) if(0<i && i<L-1 && B[y-i][x-1]!=0) { ng=false; break; }
			if(ng) rep(i,L) if(B[y-i][x  ]!=(i==0||i==L-1?7:0)) { ng=false; break; }
			if(ng) rep(i,L) if(B[y-i][x+1]!=7) { ng=false; break; }
			if(ng) return;
		}
	}

	for(int k=3;k>=0;k--){
		int xx=x+dx[k],yy=y+dy[k];
		if(0<=xx && xx<w && 0<=yy && yy<h){
			if(B[yy][xx]==2){
				ans=now+1+bfs(x3,y3,3);
				return;
			}
			else if(B[yy][xx]==0){
				B[yy][xx]=7;
				dfs(xx,yy,now+1);
				B[yy][xx]=0;
			}
		}
	}
}

int main(){
	while(scanf("%d%d",&h,&w),h){
		rep(i,h) rep(j,w) scanf("%d",B[i]+j);

		rep(i,h) rep(j,w) {
			if(B[i][j]==2) x2=j, y2=i;
			if(B[i][j]==3) x3=j, y3=i;
		}
		B[y2][x2]=7; // 訪問済みのマーク

		ans=777;
		dfs(x2,y2,0);
		printf("%d\n",ans<777?ans:0);
	}

	return 0;
}
accuracy: 1
time_ms: 200
memory_kb: 1032
final_rank: 1

code_snippet: #include<cstdio>
#include<cstring>

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

using namespace std;

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

int h,w,B[9][9];

int x2,y2,x3,y3; // 2, 3 それぞれの出発点

int bfs(int x,int y,int tar){
	int d[9][9];
	memset(d,-1,sizeof d);
	d[y][x]=0;
	int Q[81],head=0,tail=0; Q[tail++]=y*w+x;
	while(head<tail){
		int i=Q[head]/w,j=Q[head]%w; head++;
		rep(k,4){
			int yy=i+dy[k],xx=j+dx[k];
			if(0<=yy && yy<h && 0<=xx && xx<w && d[yy][xx]==-1){
				if(B[yy][xx]==tar) return d[i][j]+1;
				if(B[yy][xx]== 0 ) Q[tail++]=yy*w+xx, d[yy][xx]=d[i][j]+1;
			}
		}
	}
	return 777;
}

int ans;
void dfs(int x,int y,int now){
	int hstar=bfs(x,y,2)+bfs(x3,y3,3);
	if(ans<now+1+hstar) return;

	// これまでのパスと接したら枝刈り
	int cnt=0;
	rep(k,4){
		int xx=x+dx[k],yy=y+dy[k];
		if(0<=xx && xx<w && 0<=yy && yy<h && B[yy][xx]==7) cnt++;
	}
	if(cnt>=2) return;

	// 777...777
	// 700...007
	// ?00...00?
	// というパターン ( or 回転/反転して一致するもの ) があれば枝刈り
	for(int L=3;L<=8;L++){
		bool ng;
		if(y>0 && x+L-1<w){
			ng=true;
			if(ng) rep(j,L) if(B[y-1][x+j]!=7) { ng=false; break; }
			if(ng) rep(j,L) if(B[y  ][x+j]!=(j==0||j==L-1?7:0)) { ng=false; break; }
			if(ng && L>=5 && y+1<h) rep(j,L) if(0<j && j<L-1 && B[y+1][x+j]!=0) { ng=false; break; }
			if(ng) return;
		}
		if(y+1<h && x+L-1<w){
			ng=true;
			if(ng && L>=5 && y>0) rep(j,L) if(0<j && j<L-1 && B[y-1][x+j]!=0) { ng=false; break; }
			if(ng) rep(j,L) if(B[y  ][x+j]!=(j==0||j==L-1?7:0)) { ng=false; break; }
			if(ng) rep(j,L) if(B[y+1][x+j]!=7) { ng=false; break; }
			if(ng) return;
		}
		if(y>0 && x-L+1>=0){
			ng=true;
			if(ng) rep(j,L) if(B[y-1][x-j]!=7) { ng=false; break; }
			if(ng) rep(j,L) if(B[y  ][x-j]!=(j==0||j==L-1?7:0)) { ng=false; break; }
			if(ng && L>=5 && y+1<h) rep(j,L) if(0<j && j<L-1 && B[y+1][x-j]!=0) { ng=false; break; }
			if(ng) return;
		}
		if(y+1<h && x-L+1>=0){
			ng=true;
			if(ng && L>=5 && y>0) rep(j,L) if(0<j && j<L-1 && B[y-1][x-j]!=0) { ng=false; break; }
			if(ng) rep(j,L) if(B[y  ][x-j]!=(j==0||j==L-1?7:0)) { ng=false; break; }
			if(ng) rep(j,L) if(B[y+1][x-j]!=7) { ng=false; break; }
			if(ng) return;
		}
		if(y+L-1<h && x>0){
			ng=true;
			if(ng) rep(i,L) if(B[y+i][x-1]!=7) { ng=false; break; }
			if(ng) rep(i,L) if(B[y+i][x  ]!=(i==0||i==L-1?7:0)) { ng=false; break; }
			if(ng && L>=5 && x+1<w) rep(i,L) if(0<i && i<L-1 && B[y+i][x+1]!=0) { ng=false; break; }
			if(ng) return;
		}
		if(y+L-1<h && x+1<w){
			ng=true;
			if(ng && L>=5 && x>0) rep(i,L) if(0<i && i<L-1 && B[y+i][x-1]!=0) { ng=false; break; }
			if(ng) rep(i,L) if(B[y+i][x  ]!=(i==0||i==L-1?7:0)) { ng=false; break; }
			if(ng) rep(i,L) if(B[y+i][x+1]!=7) { ng=false; break; }
			if(ng) return;
		}
		if(y-L+1>=0 && x>0){
			ng=true;
			if(ng) rep(i,L) if(B[y-i][x-1]!=7) { ng=false; break; }
			if(ng) rep(i,L) if(B[y-i][x  ]!=(i==0||i==L-1?7:0)) { ng=false; break; }
			if(ng && L>=5 && x+1<w) rep(i,L) if(0<i && i<L-1 && B[y-i][x+1]!=0) { ng=false; break; }
			if(ng) return;
		}
		if(y-L+1>=0 && x+1<w){
			ng=true;
			if(ng && L>=5 && x>0) rep(i,L) if(0<i && i<L-1 && B[y-i][x-1]!=0) { ng=false; break; }
			if(ng) rep(i,L) if(B[y-i][x  ]!=(i==0||i==L-1?7:0)) { ng=false; break; }
			if(ng) rep(i,L) if(B[y-i][x+1]!=7) { ng=false; break; }
			if(ng) return;
		}
	}

	rep(k,4){
		int xx=x+dx[k],yy=y+dy[k];
		if(0<=xx && xx<w && 0<=yy && yy<h){
			if(B[yy][xx]==2){
				ans=now+1+bfs(x3,y3,3);
				return;
			}
			else if(B[yy][xx]==0){
				B[yy][xx]=7;
				dfs(xx,yy,now+1);
				B[yy][xx]=0;
			}
		}
	}
}

int main(){
	while(scanf("%d%d",&h,&w),h){
		rep(i,h) rep(j,w) scanf("%d",B[i]+j);

		rep(i,h) rep(j,w) {
			if(B[i][j]==2) x2=j, y2=i;
			if(B[i][j]==3) x3=j, y3=i;
		}
		B[y2][x2]=7; // 訪問済みのマーク

		ans=777;
		dfs(x2,y2,0);
		printf("%d\n",ans<777?ans:0);
	}

	return 0;
}
accuracy: 1
time_ms: 240
memory_kb: 1032
final_rank: 2

code_snippet: #include<cstdio>
#include<cstring>

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

using namespace std;

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

int h,w,B[9][9];

int x2,y2,x3,y3; // 2, 3 それぞれの出発点

int bfs(int x,int y,int tar){
	int d[9][9];
	memset(d,-1,sizeof d);
	d[y][x]=0;
	int Q[81],head=0,tail=0; Q[tail++]=y*w+x;
	while(head<tail){
		int i=Q[head]/w,j=Q[head]%w; head++;
		rep(k,4){
			int yy=i+dy[k],xx=j+dx[k];
			if(0<=yy && yy<h && 0<=xx && xx<w && d[yy][xx]==-1){
				if(B[yy][xx]==tar) return d[i][j]+1;
				if(B[yy][xx]== 0 ) Q[tail++]=yy*w+xx, d[yy][xx]=d[i][j]+1;
			}
		}
	}
	return 777;
}

int ans;
void dfs(int x,int y,int now){
	int hstar=bfs(x,y,2)+bfs(x3,y3,3);
	if(ans<now+1+hstar) return;

	// これまでのパスと接したら枝刈り
	int cnt=0;
	rep(k,4){
		int xx=x+dx[k],yy=y+dy[k];
		if(0<=xx && xx<w && 0<=yy && yy<h && B[yy][xx]==7) cnt++;
	}
	if(cnt>=2) return;

	// 777...777
	// 700...007
	// ?00...00?
	// というパターン ( or 回転して一致するもの ) があれば枝刈り
	for(int L=3;L<=8;L++){
		bool ng;
		if(y>0 && x+L-1<w){
			ng=true;
			if(ng) rep(j,L) if(B[y-1][x+j]!=7) { ng=false; break; }
			if(ng) rep(j,L) if(B[y  ][x+j]!=(j==0||j==L-1?7:0)) { ng=false; break; }
			if(ng && L>=5 && y+1<h) rep(j,L) if(0<j && j<L-1 && B[y+1][x+j]!=0) { ng=false; break; }
			if(ng) return;

			ng=true;
			if(ng && L>=5 && y-2>=0) rep(j,L) if(0<j && j<L-1 && B[y-2][x+j]!=0) { ng=false; break; }
			if(ng) rep(j,L) if(B[y-1][x+j]!=(j==0||j==L-1?7:0)) { ng=false; break; }
			if(ng) rep(j,L) if(B[y  ][x+j]!=7) { ng=false; break; }
			if(ng) return;
		}
		if(y>0 && x-L+1>=0){
			ng=true;
			if(ng) rep(j,L) if(B[y-1][x-j]!=7) { ng=false; break; }
			if(ng) rep(j,L) if(B[y  ][x-j]!=(j==0||j==L-1?7:0)) { ng=false; break; }
			if(ng && L>=5 && y+1<h) rep(j,L) if(0<j && j<L-1 && B[y+1][x-j]!=0) { ng=false; break; }
			if(ng) return;

			ng=true;
			if(ng && L>=5 && y-2>=0) rep(j,L) if(0<j && j<L-1 && B[y-2][x-j]!=0) { ng=false; break; }
			if(ng) rep(j,L) if(B[y-1][x-j]!=(j==0||j==L-1?7:0)) { ng=false; break; }
			if(ng) rep(j,L) if(B[y  ][x-j]!=7) { ng=false; break; }
			if(ng) return;
		}
		if(y+L-1<h && x+1<w){
			ng=true;
			if(ng) rep(i,L) if(B[y+i][x  ]!=7) { ng=false; break; }
			if(ng) rep(i,L) if(B[y+i][x+1]!=(i==0||i==L-1?7:0)) { ng=false; break; }
			if(ng && L>=5 && x+2<w) rep(i,L) if(0<i && i<L-1 && B[y+i][x+2]!=0) { ng=false; break; }
			if(ng) return;

			ng=true;
			if(ng && L>=5 && x-1>=0) rep(i,L) if(0<i && i<L-1 && B[y+i][x-1]!=0) { ng=false; break; }
			if(ng) rep(i,L) if(B[y+i][x  ]!=(i==0||i==L-1?7:0)) { ng=false; break; }
			if(ng) rep(i,L) if(B[y+i][x+1]!=7) { ng=false; break; }
			if(ng) return;
		}
		if(y-L+1>=0 && x+1<w){
			ng=true;
			if(ng) rep(i,L) if(B[y-i][x  ]!=7) { ng=false; break; }
			if(ng) rep(i,L) if(B[y-i][x+1]!=(i==0||i==L-1?7:0)) { ng=false; break; }
			if(ng && L>=5 && x+2<w) rep(i,L) if(0<i && i<L-1 && B[y-i][x+2]!=0) { ng=false; break; }
			if(ng) return;

			ng=true;
			if(ng && L>=5 && x-1>=0) rep(i,L) if(0<i && i<L-1 && B[y-i][x-1]!=0) { ng=false; break; }
			if(ng) rep(i,L) if(B[y-i][x  ]!=(i==0||i==L-1?7:0)) { ng=false; break; }
			if(ng) rep(i,L) if(B[y-i][x+1]!=7) { ng=false; break; }
			if(ng) return;
		}
	}

	rep(k,4){
		int xx=x+dx[k],yy=y+dy[k];
		if(0<=xx && xx<w && 0<=yy && yy<h){
			if(B[yy][xx]==2){
				ans=now+1+bfs(x3,y3,3);
				return;
			}
			else if(B[yy][xx]==0){
				B[yy][xx]=7;
				dfs(xx,yy,now+1);
				B[yy][xx]=0;
			}
		}
	}
}

int main(){
	while(scanf("%d%d",&h,&w),h){
		rep(i,h) rep(j,w) scanf("%d",B[i]+j);

		rep(i,h) rep(j,w) {
			if(B[i][j]==2) x2=j, y2=i;
			if(B[i][j]==3) x3=j, y3=i;
		}
		B[y2][x2]=7; // 訪問済みのマーク

		ans=777;
		dfs(x2,y2,0);
		printf("%d\n",ans<777?ans:0);
	}

	return 0;
}
accuracy: 1
time_ms: 1110
memory_kb: 1032
final_rank: 3

code_snippet: #include<cstdio>
#include<cstring>

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

using namespace std;

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

int h,w,B[9][9];

int x2,y2,x3,y3; // 2, 3 それぞれの出発点

int bfs(int x,int y,int tar){
	int d[9][9];
	memset(d,-1,sizeof d);
	d[y][x]=0;
	int Q[81],head=0,tail=0; Q[tail++]=y*w+x;
	while(head<tail){
		int i=Q[head]/w,j=Q[head]%w; head++;
		rep(k,4){
			int yy=i+dy[k],xx=j+dx[k];
			if(0<=yy && yy<h && 0<=xx && xx<w && d[yy][xx]==-1){
				if(B[yy][xx]==tar) return d[i][j]+1;
				if(B[yy][xx]== 0 ) Q[tail++]=yy*w+xx, d[yy][xx]=d[i][j]+1;
			}
		}
	}
	return 777;
}

int ans;
void dfs(int x,int y,int now){
	int hstar=bfs(x,y,2)+bfs(x3,y3,3);
	if(ans<now+1+hstar) return;

	// これまでのパスと接したら枝刈り
	int cnt=0;
	rep(k,4){
		int xx=x+dx[k],yy=y+dy[k];
		if(0<=xx && xx<w && 0<=yy && yy<h && B[yy][xx]==7) cnt++;
	}
	if(cnt>=2) return;

	// 777...777
	// 700...007
	// というパターン ( or 回転して一致するもの ) があれば枝刈り
	for(int L=3;L<=8;L++){
		bool ng;
		if(y>0 && x+L-1<w){
			ng=true;
			if(ng) rep(j,L) if(B[y-1][x+j]!=7) { ng=false; break; }
			if(ng) rep(j,L) if(B[y  ][x+j]!=(j==0||j==L-1?7:0)) { ng=false; break; }
			if(ng && y+1<h) rep(j,L) if(0<j && j<L-1 && B[y+1][x+j]!=0) { ng=false; break; }
			if(ng) return;

			ng=true;
			if(ng && y-2>=0) rep(j,L) if(0<j && j<L-1 && B[y-2][x+j]!=0) { ng=false; break; }
			if(ng) rep(j,L) if(B[y-1][x+j]!=(j==0||j==L-1?7:0)) { ng=false; break; }
			if(ng) rep(j,L) if(B[y  ][x+j]!=7) { ng=false; break; }
			if(ng) return;
		}
		if(y>0 && x-L+1>=0){
			ng=true;
			if(ng) rep(j,L) if(B[y-1][x-j]!=7) { ng=false; break; }
			if(ng) rep(j,L) if(B[y  ][x-j]!=(j==0||j==L-1?7:0)) { ng=false; break; }
			if(ng && y+1<h) rep(j,L) if(0<j && j<L-1 && B[y+1][x-j]!=0) { ng=false; break; }
			if(ng) return;

			ng=true;
			if(ng && y-2>=0) rep(j,L) if(0<j && j<L-1 && B[y-2][x-j]!=0) { ng=false; break; }
			if(ng) rep(j,L) if(B[y-1][x-j]!=(j==0||j==L-1?7:0)) { ng=false; break; }
			if(ng) rep(j,L) if(B[y  ][x-j]!=7) { ng=false; break; }
			if(ng) return;
		}
		if(y+L-1<h && x+1<w){
			ng=true;
			if(ng) rep(i,L) if(B[y+i][x  ]!=7) { ng=false; break; }
			if(ng) rep(i,L) if(B[y+i][x+1]!=(i==0||i==L-1?7:0)) { ng=false; break; }
			if(ng && x+2<w) rep(i,L) if(0<i && i<L-1 && B[y+i][x+2]!=0) { ng=false; break; }
			if(ng) return;

			ng=true;
			if(ng && x-1>=0) rep(i,L) if(0<i && i<L-1 && B[y+i][x-1]!=0) { ng=false; break; }
			if(ng) rep(i,L) if(B[y+i][x  ]!=(i==0||i==L-1?7:0)) { ng=false; break; }
			if(ng) rep(i,L) if(B[y+i][x+1]!=7) { ng=false; break; }
			if(ng) return;
		}
		if(y-L+1>=0 && x+1<w){
			ng=true;
			if(ng) rep(i,L) if(B[y-i][x  ]!=7) { ng=false; break; }
			if(ng) rep(i,L) if(B[y-i][x+1]!=(i==0||i==L-1?7:0)) { ng=false; break; }
			if(ng && x+2<w) rep(i,L) if(0<i && i<L-1 && B[y-i][x+2]!=0) { ng=false; break; }
			if(ng) return;

			ng=true;
			if(ng && x-1>=0) rep(i,L) if(0<i && i<L-1 && B[y-i][x-1]!=0) { ng=false; break; }
			if(ng) rep(i,L) if(B[y-i][x  ]!=(i==0||i==L-1?7:0)) { ng=false; break; }
			if(ng) rep(i,L) if(B[y-i][x+1]!=7) { ng=false; break; }
			if(ng) return;
		}
	}

	rep(k,4){
		int xx=x+dx[k],yy=y+dy[k];
		if(0<=xx && xx<w && 0<=yy && yy<h){
			if(B[yy][xx]==2){
				ans=now+1+bfs(x3,y3,3);
				return;
			}
			else if(B[yy][xx]==0){
				B[yy][xx]=7;
				dfs(xx,yy,now+1);
				B[yy][xx]=0;
			}
		}
	}
}

int main(){
	while(scanf("%d%d",&h,&w),h){
		rep(i,h) rep(j,w) scanf("%d",B[i]+j);

		rep(i,h) rep(j,w) {
			if(B[i][j]==2) x2=j, y2=i;
			if(B[i][j]==3) x3=j, y3=i;
		}
		B[y2][x2]=7; // 訪問済みのマーク

		ans=777;
		dfs(x2,y2,0);
		printf("%d\n",ans<777?ans:0);
	}

	return 0;
}
accuracy: 1
time_ms: 1350
memory_kb: 1036
final_rank: 6

code_snippet: #include<cstdio>
#include<cstring>
#include<sys/time.h>

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

using namespace std;

typedef long long ll;

ll gettime(){
	struct timeval tv;
	gettimeofday(&tv,NULL);
	return 1000000LL*tv.tv_sec+tv.tv_usec;
}

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

int h,w,B[9][9];

int x2,y2,x3,y3; // 2, 3 それぞれの出発点

int bfs(int x,int y,int tar){
	int d[9][9];
	memset(d,-1,sizeof d);
	d[y][x]=0;
	int Q[81],head=0,tail=0; Q[tail++]=y*w+x;
	while(head<tail){
		int i=Q[head]/w,j=Q[head]%w; head++;
		rep(k,4){
			int yy=i+dy[k],xx=j+dx[k];
			if(0<=yy && yy<h && 0<=xx && xx<w && d[yy][xx]==-1){
				if(B[yy][xx]==tar) return d[i][j]+1;
				if(B[yy][xx]== 0 ) Q[tail++]=yy*w+xx, d[yy][xx]=d[i][j]+1;
			}
		}
	}
	return 777;
}

ll t0;

int ans;
void dfs(int x,int y,int now){
	int hstar=bfs(x,y,2)+bfs(x3,y3,3);
	if(ans<now+1+hstar) return;

	if(ans==777){ // 0.5 秒の間に一つも解が見つからなければ解なし
		ll t1=gettime();
		if(t1-t0>500000){ ans=0; return; }
	}

	// これまでのパスと接したら最適解でないので探索打ち切り
	int cnt=0;
	rep(k,4){
		int xx=x+dx[k],yy=y+dy[k];
		if(0<=xx && xx<w && 0<=yy && yy<h && B[yy][xx]==7) cnt++;
	}
	if(cnt>=2) return;

	rep(k,4){
		int xx=x+dx[k],yy=y+dy[k];
		if(0<=xx && xx<w && 0<=yy && yy<h){
			if(B[yy][xx]==2){
				ans=now+1+bfs(x3,y3,3);
				return;
			}
			else if(B[yy][xx]==0){
				B[yy][xx]=7;
				dfs(xx,yy,now+1);
				B[yy][xx]=0;
			}
		}
	}
}

int main(){
	while(scanf("%d%d",&h,&w),h){
		rep(i,h) rep(j,w) scanf("%d",B[i]+j);

		rep(i,h) rep(j,w) {
			if(B[i][j]==2) x2=j, y2=i;
			if(B[i][j]==3) x3=j, y3=i;
		}
		B[y2][x2]=7; // 訪問済みのマーク

		t0=gettime();
		ans=777;
		dfs(x2,y2,0);
		printf("%d\n",ans<777?ans:0);
	}

	return 0;
}
accuracy: 1
time_ms: 1820
memory_kb: 1028
final_rank: 7

code_snippet: #include<cstdio>
#include<cstring>
#include<sys/time.h>

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

using namespace std;

typedef long long ll;

ll gettime(){
	struct timeval tv;
	gettimeofday(&tv,NULL);
	return 1000000LL*tv.tv_sec+tv.tv_usec;
}

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

int h,w,B[9][9];

int x2,y2,x3,y3; // 2, 3 それぞれの出発点

int bfs(int x,int y,int tar){
	int d[9][9];
	memset(d,-1,sizeof d);
	d[y][x]=0;
	int Q[81],head=0,tail=0; Q[tail++]=y*w+x;
	while(head<tail){
		int i=Q[head]/w,j=Q[head]%w; head++;
		rep(k,4){
			int yy=i+dy[k],xx=j+dx[k];
			if(0<=yy && yy<h && 0<=xx && xx<w && d[yy][xx]==-1){
				if(B[yy][xx]==tar) return d[i][j]+1;
				if(B[yy][xx]== 0 ) Q[tail++]=yy*w+xx, d[yy][xx]=d[i][j]+1;
			}
		}
	}
	return 777;
}

ll t0;

int ans;
void dfs(int x,int y,int now){
	int hstar=bfs(x,y,2)+bfs(x3,y3,3);
	if(ans<now+1+hstar) return;

	if(ans==777){ // 1 秒の間に一つも解が見つからなければ解なし
		ll t1=gettime();
		if(t1-t0>1000000){ ans=0; return; }
	}

	// これまでのパスと接したら最適解でないので探索打ち切り
	int cnt=0;
	rep(k,4){
		int xx=x+dx[k],yy=y+dy[k];
		if(0<=xx && xx<w && 0<=yy && yy<h && B[yy][xx]==7) cnt++;
	}
	if(cnt>=2) return;

	rep(k,4){
		int xx=x+dx[k],yy=y+dy[k];
		if(0<=xx && xx<w && 0<=yy && yy<h){
			if(B[yy][xx]==2){
				ans=now+1+bfs(x3,y3,3);
				return;
			}
			else if(B[yy][xx]==0){
				B[yy][xx]=7;
				dfs(xx,yy,now+1);
				B[yy][xx]=0;
			}
		}
	}
}

int main(){
	while(scanf("%d%d",&h,&w),h){
		rep(i,h) rep(j,w) scanf("%d",B[i]+j);

		rep(i,h) rep(j,w) {
			if(B[i][j]==2) x2=j, y2=i;
			if(B[i][j]==3) x3=j, y3=i;
		}
		B[y2][x2]=7; // 訪問済みのマーク

		t0=gettime();
		ans=777;
		dfs(x2,y2,0);
		printf("%d\n",ans<777?ans:0);
	}

	return 0;
}
accuracy: 1
time_ms: 2320
memory_kb: 1028
final_rank: 10

code_snippet: #include<cstdio>
#include<cstring>
#include<sys/time.h>

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

using namespace std;

typedef long long ll;

ll gettime(){
	struct timeval tv;
	gettimeofday(&tv,NULL);
	return 1000000LL*tv.tv_sec+tv.tv_usec;
}

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

int h,w,B[9][9];

int x2,y2,x3,y3; // 2, 3 それぞれの出発点

int bfs(int x,int y,int tar){
	int d[9][9];
	memset(d,-1,sizeof d);
	d[y][x]=0;
	int Q[81],head=0,tail=0; Q[tail++]=y*w+x;
	while(head<tail){
		int i=Q[head]/w,j=Q[head]%w; head++;
		rep(k,4){
			int yy=i+dy[k],xx=j+dx[k];
			if(0<=yy && yy<h && 0<=xx && xx<w && d[yy][xx]==-1){
				if(B[yy][xx]==tar) return d[i][j]+1;
				if(B[yy][xx]== 0 ) Q[tail++]=yy*w+xx, d[yy][xx]=d[i][j]+1;
			}
		}
	}
	return 777;
}

ll t0;

int ans;
void dfs(int x,int y,int now){
	int hstar=bfs(x,y,2)+bfs(x3,y3,3);
	if(ans<now+1+hstar) return;

	if(ans==777){ // 3 秒の間に一つも解が見つからなければ解なし
		ll t1=gettime();
		if(t1-t0>3000000){ ans=0; return; }
	}

	// これまでのパスと接したら最適解でないので探索打ち切り
	int cnt=0;
	rep(k,4){
		int xx=x+dx[k],yy=y+dy[k];
		if(0<=xx && xx<w && 0<=yy && yy<h && B[yy][xx]==7) cnt++;
	}
	if(cnt>=2) return;

	rep(k,4){
		int xx=x+dx[k],yy=y+dy[k];
		if(0<=xx && xx<w && 0<=yy && yy<h){
			if(B[yy][xx]==2){
				ans=now+1+bfs(x3,y3,3);
				return;
			}
			else if(B[yy][xx]==0){
				B[yy][xx]=7;
				dfs(xx,yy,now+1);
				B[yy][xx]=0;
			}
		}
	}
}

int main(){
	while(scanf("%d%d",&h,&w),h){
		rep(i,h) rep(j,w) scanf("%d",B[i]+j);

		rep(i,h) rep(j,w) {
			if(B[i][j]==2) x2=j, y2=i;
			if(B[i][j]==3) x3=j, y3=i;
		}
		B[y2][x2]=7; // 訪問済みのマーク

		t0=gettime();
		ans=777;
		dfs(x2,y2,0);
		printf("%d\n",ans<777?ans:0);
	}

	return 0;
}
accuracy: 1
time_ms: 2840
memory_kb: 1028
final_rank: 11

code_snippet: #include<iostream>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)

const int N = 9;
const int inf = (1 <<21);

int dx[]={0,1, 0,-1};
int dy[]={1,0,-1,0};
int op[]={2,3, 0,1};
int m[N][N];
bool vis2[N][N];

bool isok(int r,int c,int y,int x,int last){
  rep(i,4){
    if (op[i] == last)continue;
    int nex=x+dx[i],ney=y+dy[i];
    if (nex==-1||ney==-1||nex==c||ney==r)continue;
    if (vis2[ney][nex])return false;
  }
  return true;
}

int ans;
bool isgoal;
int md;
bool bfs(int r,int c,int cnt,bool goal2){
  static int q[N*N];
  static int cost[N][N];
  int sy3=-1,sx3=-1,gy3=-1,gx3=-1;
  rep(i,r){
    rep(j,c){
      if (m[i][j] == 3){
	if (sy3==-1)sy3=i,sx3=j;
	else gy3=i,gx3=j;
      }
      cost[i][j]=inf;
    }
  }
  int tail=0,head=0;
  q[tail++]=sx3+sy3*c;
  cost[sy3][sx3]=0;
  while(head != tail){
    int now = q[head++];
    int x = now%c,y=now/c;
    if (cnt+cost[y][x] >= ans)return false;
    if (x == gx3 && y == gy3){
      if (goal2)return true;
      isgoal=true;
      ans =min(ans,cnt+cost[y][x]);
      return true;
    }
    rep(i,4){
      int nex=x+dx[i],ney=y+dy[i];
      if (nex==-1||ney==-1||nex==c||ney==r||vis2[ney][nex])continue;
      if (m[ney][nex]==1||m[ney][nex] == 2)continue;
      if (cost[ney][nex] != inf)continue;
      cost[ney][nex]=cost[y][x]+1;
      q[tail++]=ney*c+nex;
    }
  }
  return false;
}

int path[N*N];
int pattern[8][4]={
  {2,1,1,0,},
  {1,0,0,3,},
  {0,3,3,2,},
  {3,2,2,1,},
  {2,3,3,0,},
  {1,2,2,3,},
  {0,1,1,2,},
  {3,0,0,1,},
};

int cx[]={-1, 0,1, 0, 1, 0,-1, 0};
int cy[]={ 0,-1,0, 1, 0, 1, 0,-1};

bool isok2(int r,int c,int y,int x,int p){
  if (p <4)return true;
  rep(i,8){
    bool ismatch=true;
    rep(j,4){
      if (pattern[i][j] == path[p-(4-j)]);
      else ismatch=false;
    }
    if (!ismatch)continue;
    int nex=x+cx[i],ney=y+cy[i];
    if (nex==-1||ney==-1||nex==c||ney==r)continue;
    if (m[ney][nex] == 0 && !vis2[ney][nex])return false;

  }
  return true;
}

void dfs(int r,int c,int y,int x,int cnt,int last,int gy2,int gx2){
  if (!isok(r,c,y,x,last)){
    return;
  }
  if (!isok2(r,c,y,x,cnt))return;

  if (cnt+md >= ans)return;
  //  if (!bfs(r,c,cnt,true))return;

  if (x == gx2 && y == gy2){
    vis2[y][x]=true;
    bfs(r,c,cnt,false);
    vis2[y][x]=false;
    return;
  }

  vis2[y][x]=true;
  rep(i,4){
    if (op[i] == last)continue;
    int nex=x+dx[i],ney=y+dy[i];
    if (nex==-1||ney==-1||nex==c||ney==r||vis2[ney][nex])continue;
    if (m[ney][nex] == 3 || m[ney][nex] == 1)continue;
    path[cnt]=i;
    dfs(r,c,ney,nex,cnt+1,i,gy2,gx2);
  }
  vis2[y][x]=false;
}

int bfs2(int r,int c,int tar,int utar){
  static int q[N*N];
  static int cost[N][N];
  int sy3=-1,sx3=-1,gy3=-1,gx3=-1;
  rep(i,r){
    rep(j,c){
      if (m[i][j] == tar){
	if (sy3==-1)sy3=i,sx3=j;
	else gy3=i,gx3=j;
      }
      cost[i][j]=inf;
    }
  }
  int tail=0,head=0;
  q[tail++]=sx3+sy3*c;
  cost[sy3][sx3]=0;
  while(head != tail){
    int now = q[head++];
    int x = now%c,y=now/c;
    if (x == gx3 && y == gy3){
      return cost[y][x];
    }
    rep(i,4){
      int nex=x+dx[i],ney=y+dy[i];
      if (nex==-1||ney==-1||nex==c||ney==r||vis2[ney][nex])continue;
      if (m[ney][nex]==1||m[ney][nex] == utar)continue;
      if (cost[ney][nex] != inf)continue;
      cost[ney][nex]=cost[y][x]+1;
      q[tail++]=ney*c+nex;
    }
  }
  return false;
}

main(){
  int r,c;
  while(cin>>r>>c && r){
    ans = r*c;
    isgoal=false;
    rep(i,r)rep(j,c)cin>>m[i][j];
    rep(i,r)rep(j,c)vis2[i][j]=false;
   
    int sx2=-1,sy2=-1;
    int gx2=-1,gy2=-1;
    rep(i,r){
      rep(j,c){
	if (m[i][j] == 2){
	  if (sx2 == -1)sx2=j,sy2=i;
	  else gx2=j,gy2=i;
	}
      }
    }
    
    int sx3=-1,sy3=-1,gx3=-1,gy3=-1;
    rep(i,r){
      rep(j,c){
	if (m[i][j] == 3){
	  if (sx3 == -1)sx3=j,sy3=i;
	  else gx3=j,gy3=i;
	}
      }
    }

    md=bfs2(r,c,3,2);
    
    dfs(r,c,sy2,sx2,0,-1,gy2,gx2);
    
    if (isgoal)cout << ans << endl;
    else cout << 0 << endl;
  }
  return false;
}
accuracy: 1
time_ms: 2940
memory_kb: 868
final_rank: 12