Problem:
A Broken Door
There is a rectangular maze consisting of a number of square rooms
arranged in grid. The maze is surrounded by
walls except for its entry and exit.  The entry to the maze is at the
leftmost part of the upper side of the rectangular area, that is, the
upper side of the uppermost leftmost room of the maze is open. The
exit is located at the rightmost part of the lower side, likewise.
There is a wall between each pair of vertically or horizontally adjacent rooms. Such a wall has either
a door with a card key lock, or no door at all. If you insert a card
to a door, the door opens and you can pass the door. The opened door
will close immediately, and the inserted card won't return. You can
open any door with any card. You cannot go
through a wall that has no door.
When a maze map is given, you can easily determine how many cards are
needed to pass through the maze from the entry to the exit. In the
maze in Figure G-1, you can pass through it with ten cards,
following the path represented by the green arrows (
) in Figure G-2.
Figure G-1: A map of a maze
Figure G-2: One of the shortest paths
Now, you are informed that one of the doors is broken and can't be
passed. But you don't know which door is broken. If you insert a card
to a broken door, the inserted card immediately returns. However,
you can't tell a broken door from a working door just by its
appearance.
Figure G-3: A maze that potentially can't be passed through
If the door marked with a red X (
) in Figure G-3 is broken, you have no way to pass through
the maze from the entry to the exit. However, you can pass the maze in
Figure G-1 whichever door is broken. When you intend to follow the
shortest path in Figure G-2, and find that the door marked with a red X in Figure G-4 is broken, you
might follow the path represented as green arrows. In this case, you
need twenty cards.
Figure G-4: A maze with a broken door
However, you can pass through the maze with less cards.  You should
follow the path in Figure G-5, until you find the broken door.
The path is not the shortest path because it needs twelve
cards at least. After you've found a broken door on the path, you
should follow the shortest path to the exit that doesn't use the broken
door. With this strategy, you can pass the maze with sixteen cards
whichever door is broken.  Figure G-6 shows one of the worst cases of
this strategy; it needs sixteen cards.
Figure G-5: The path before you find the broken door
Figure G-6: One of the worst cases of the strategy
You are requested to write a program that prints the minimum number of
cards to pass the maze whichever door is broken.
Input
The input consists of one or more datasets, each of which represents a
maze. The number of datasets is no more than 100.
The first line of a dataset contains two integer numbers, the
height
h
and the width
w
of the rectangular maze, in
this order. You may assume that 2 ≤ h, w ≤ 30.
The following 2 ×
h
− 1 lines of a dataset describe
whether there are doo
...(truncated)

Submitted solutions:

code_snippet: #include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int n, m, bak, cl, qx[909], qy[909], dis[33][33], pas[77][77], x, y, dx[4], dy[4], mn[33][33], ans[77][77][2];
int main()
{
	dx[0] = -1; dy[0] = 0;
	dx[1] = 0; dy[1] = -1;
	dx[2] = +1; dy[2] = 0;
	dx[3] = 0; dy[3] = +1;
		for(;;)
	{
	for(int i = 0; i < 77; i++) for(int j = 0; j < 77; j++) pas[i][j] = 1;
		scanf("%d%d", &n, &m);
		if(!n or !m)
			break;
		//printf("%d %d\n", n, m);
		for(int i = 1; i <= 2 * n - 1; i++)
		{
			if(i & 1)
			{
				for(int j = 1; j < m; j++)
				{
					scanf("%d", &pas[i + 1][j * 2 + 1]);
				}
			}else
			{
				for(int j = 1; j <= m; j++)
				{
					scanf("%d", &pas[i + 1][j * 2]);
				}
			}
		}
		bool flag = true;
		for(int i = 2; i <= 2 * n; i++) for(int j = 2; j <= 2 * m; j++) if(i % 2 == 1 xor j % 2 == 1)
		{
			//	printf("%d %d\n", i,j);
			bak = pas[i][j];
			pas[i][j] = 1;

			qx[cl = 1] = n;
			qy[1] = m;
			for(int i1 = 1; i1 <= n; i1++) for(int j1 = 1; j1 <= m; j1++) dis[i1][j1] = -1;
			dis[n][m] = 0;
			for(int op = 1; op <= cl; op++)
			{
			//	printf("%d\n", op);
				x = qx[op]; y = qy[op];
				for(int d = 0; d < 4; d++)
				{
				//	printf("%d %d\n", x + dx[d], y + dy[d]);
					if(!pas[2 * x + dx[d]][2 * y + dy[d]] and dis[x + dx[d]][y + dy[d]] == -1)
					{
						dis[x + dx[d]][y + dy[d]] = dis[x][y] + 1;
						qx[++cl] = x + dx[d];
						qy[cl] = y + dy[d];
					}
				}
			}
			if(dis[1][1] == -1) {flag = false; break;}
			ans[i][j][0] = dis[i / 2][j / 2];
			ans[i][j][1] = dis[(i + 1) / 2][(j + 1) / 2];
		//	printf("ans[%d][%d][%d] = %d, ans[%d][%d][%d] = %d, \n", i, j,0, ans[i][j][0], i, j, 1, ans[i][j][1]);
			pas[i][j] = bak;
		}
		if(!flag) {printf("-1\n"); continue;}
		for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) mn[i][j] = 0x3fffffff;
		mn[n][m] = 0;
		qx[cl = 1] = n;
		qy[1] = m;
		for(int op = 1; op <= cl; op++)
		{
			x = qx[op]; y = qy[op];
			for(int d = 0; d < 4; d++)if(!pas[x * 2 + dx[d]][y * 2 + dy[d]])
			{
				int tmp = max(1 + mn[x][y], ans[x * 2 + dx[d]][y * 2 + dy[d]][(dx[d] + dy[d]) == 1?1:0]);
				//printf("%d %d %d\n", x, y, tmp);
				if(mn[x + dx[d]][y + dy[d]] > tmp)
				{
					mn[x + dx[d]][y + dy[d]] = tmp;
					qx[++cl] = x + dx[d];
					qy[cl] = y + dy[d];
				}
			}
		}
		printf("%d\n", mn[1][1]);
	}
	fclose(stdin);
	return 0;
}
accuracy: 1
time_ms: 170
memory_kb: 3052
final_rank: 1

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

using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}

/**
 * @brief template
 */

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

int main() {
while(1) {
    int N, M;
    cin >> N >> M;
    if (N == 0 && M == 0) return 0;
    vector B(N, vector(M, vector<bool>(4,false)));
    rep(i,0,N-1) {
        rep(j,0,M-1) {
            int A;
            cin >> A;
            if (A == 0) {
                B[i][j][0] = true;
                B[i][j+1][2] = true;
            }
        }
        rep(j,0,M) {
            int A;
            cin >> A;
            if (A == 0) {
                B[i][j][1] = true;
                B[i+1][j][3] = true;
            }
        }
    }
    rep(j,0,M-1) {
        int A;
        cin >> A;
        if (A == 0) {
            B[N-1][j][0] = true;
            B[N-1][j+1][2] = true;
        }
    }
    vector Dist(N, vector(M, vector<int>(4,inf)));
    auto getDist = [&](int SX, int SY) -> int {
        vector D(N, vector<int>(M, inf));
        queue<pair<int,int>> Q;
        Q.push({SX,SY});
        D[SX][SY] = 0;
        while(!Q.empty()) {
            auto [X, Y] = Q.front();
            Q.pop();
            rep(i,0,4) {
                if (!B[X][Y][i]) continue;
                int NX = X + dx[i], NY = Y + dy[i];
                if (chmin(D[NX][NY], D[X][Y] + 1)) {
                    Q.push({NX,NY});
                }
            }
        }
        return D[N-1][M-1];
    };
    rep(i,0,N) {
        rep(j,0,M) {
            rep(k,0,4) {
                if (!B[i][j][k]) continue;
                B[i][j][k] = false;
                Dist[i][j][k] = getDist(i,j);
                B[i][j][k] = true;
            }
        }
    }
    vector ANS(N, vector<int>(M, inf));
    ANS[N-1][M-1] = 0;
    int Time = N * M * 3;
    while(Time--) {
        rep(i,0,N) {
            rep(j,0,M) {
                rep(k,0,4) {
                    if (!B[i][j][k]) continue;
                    int ni = i + dx[k], nj = j + dy[k];
                    chmin(ANS[i][j], max(ANS[ni][nj]+1, Dist[i][j][k]));
                }
            }
        }
    }
    cout << (ANS[0][0] == inf ? -1 : ANS[0][0]) << endl;
}
}
accuracy: 1
time_ms: 720
memory_kb: 3592
final_rank: 12

code_snippet: #include<bits/stdc++.h>
using namespace std;
using ll = long long;
using vll = vector<ll>;
#define rep(i,n) for(ll i=0;i<n;i++)
#define all(A) A.begin(),A.end()


vll dx = { 1,0,-1,0 };
vll dy = { 0,-1,0,1 };

void solve(ll H, ll W) {
    vector<vll> G(H, vll(W, 0));
    rep(i, 2 * H - 1) {
        if (i % 2 == 1) {
            rep(w, W) {
                ll a;
                cin >> a;
                if (a == 0) {
                    G[i / 2][w] += 8;
                    G[i / 2 + 1][w] += 2;
                }
            }
        }
        else {
            rep(w, W - 1) {
                ll a;
                cin >> a;
                if (a == 0) {
                    G[i / 2][w] += 1;
                    G[i / 2][w + 1] += 4;
                }
            }
        }
    }
    vector<vll> WD(H, vll(W, 0));
    rep(h, H)rep(w, W)rep(e, 4) {
        vector<vll> dis(H, vll(W, 1e18)); dis[h][w] = 0;
        queue<pair<ll, ll>> Q;
        Q.push({ h,w });
        while (!Q.empty()) {
            ll y = Q.front().first;
            ll x = Q.front().second;
            Q.pop();
            ll nd = dis[y][x];
            rep(d, 4) {
                ll ny = y + dy[d];
                ll nx = x + dx[d];
                if (ny < 0 || nx < 0 || ny >= H || nx >= W)continue;
                if (y == h && x == w && d == e)continue;
                if (G[y][x] & (1 << d)) {
                    if (dis[ny][nx] > nd + 1) {
                        dis[ny][nx] = nd + 1;
                        Q.push({ ny,nx });
                    }
                }
            }
        }
        WD[h][w] = max(WD[h][w], dis[H - 1][W - 1]);
    }
    ll L = 0, R = 1e18;
    while (R - L > 1) {
        ll M = (R + L) / 2;
        if (WD[0][0] > M) {
            L = M;
            continue;
        }
        queue<pair<ll, ll>> Q;
        Q.push({ 0,0 });
        vector<vector<bool>> seen(H, vector<bool>(W, 0));
        vector<vll> dis(H, vll(W, 1e18));
        dis[0][0] = 0;
        while (!Q.empty()) {
            ll y = Q.front().first;
            ll x = Q.front().second;
            Q.pop();
            if (seen[y][x])continue;
            seen[y][x] = 1;
            rep(d, 4) {
                if (G[y][x] & (1 << d)) {
                    ll ny = y + dy[d];
                    ll nx = x + dx[d];
                    if (dis[ny][nx] > dis[y][x] + 1) {
                        dis[ny][nx] = dis[y][x] + 1;
                        if (dis[ny][nx] + WD[ny][nx] <= M) {
                            Q.push({ ny,nx });
                        }
                    }
                }
            }
        }
        (seen[H - 1][W - 1] ? R : L) = M;
    }
    cout << (R < 1e17 ? R : -1) << endl;

}

int main() {

    ll H, W;
    while (cin >> H >> W) {
        if (H == 0)return 0;
        solve(H, W);
    }
}
accuracy: 1
time_ms: 1290
memory_kb: 3436
final_rank: 17

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

using ll = long long;

bool is_end = false;

//   2
// 3 * 1
//   0
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};


void solve()
{
    int H, W; cin >> H >> W;
    if (H == 0 && W == 0)
    {
        is_end = true;
        return;
    }
    
    vector<vector<int>> pair_to_num(H, vector<int>(W));
    vector<pair<int, int>> num_to_pair(H * W);
    for (int i = 0; i < H; ++i)
    {
        for (int j = 0; j < W; ++j)
        {
            pair_to_num[i][j] = i * W + j;
            num_to_pair[i * W + j] = {i, j};
        }
    }
    
    vector<vector<int>> graph(H * W, vector<int>(4, -1));
    for (int i = 0; i < 2 * H - 1; ++i)
    {
        if (i % 2 == 0)
        {
            for (int j = 0; j < W - 1; ++j)
            {
                int left = pair_to_num[i/2][j];
                int right = pair_to_num[i/2][j+1];
                
                int c; cin >> c;
                if (c == 0)
                {
                    graph[left][1] = right;
                    graph[right][3] = left;
                }
                
            }
        }
        else
        {
            for (int j = 0; j < W; ++j)
            {
                int up = pair_to_num[i/2][j];
                int down = pair_to_num[i/2+1][j];
                
                int c; cin >> c;
                if (c == 0)
                {
                    graph[up][0] = down;
                    graph[down][2] = up;
                }
                
            }
        }
        
    }
    
    int S = 0, T = H * W - 1;
    const int INF = 1e9;
    vector<vector<int>> dist_to_T(H * W, vector<int>(4, INF));
    
    for (int x = 0; x < H; ++x)
    {
        for (int y = 0; y < W; ++y)
        {
            for (int dir = 0; dir < 4; ++dir)
            {
                int v = pair_to_num[x][y];
                int nv = graph[v][dir];
                
                if (nv == -1) continue;
                
                {
                    vector<int> dist(H * W, INF);
                    queue<int> que;
                    
                    que.push(v);
                    dist[v] = 0;
                    
                    while (!que.empty())
                    {
                        int u = que.front();
                        que.pop();
                        
                        for (auto nu : graph[u])
                        {
                            if (nu == -1) continue;
                            if (dist[nu] < INF) continue;
                            if (u == v && nu == nv) continue;
                            dist[nu] = dist[u] + 1;
                            que.push(nu);
                        }
                    }
                    
                    
                    dist_to_T[v][dir] = dist[T];
                    
                    // cout << x << " " << y << " " << dir << " " << dist_to_T[v][dir] << endl;
                }
                
            }
        }
    }
    
    // for (int dir = 0; dir < 4; ++dir)
    // {
    //     cout << dir << " " << dist_to_T[0][dir] << endl;
    // }
    
    int ok = INF, ng = 0;
    while (abs(ok - ng) > 1)
    {
        int mid = (ok + ng) / 2;
        
        {
            vector<int> dist(H * W, INF);
            queue<int> que;
            
            que.push(S);
            dist[S] = 0;
            
            while (!que.empty())
            {
                int v = que.front();
                que.pop();
                
                for (int dir = 0; dir < 4; ++dir)
                {
                    int nv = graph[v][dir];
                    if (nv == -1) continue;
                    if (dist[nv] < INF) continue;
                    
                    int sum = dist[v] + dist_to_T[v][dir];
                    if (sum <= mid)
                    {
                        // if (v == 0 && dir == 0) cout << sum << " " << mid << endl;
                        dist[nv] = dist[v] + 1;
                        que.push(nv);
                    }
                }
            }
            
            if (dist[T] < INF) ok = mid;
            else ng = mid;
        }
        
    }
    
    if (ok == INF) ok = -1;
    cout << ok << endl;
    
    
    return;
}

int main()
{
    while (!is_end)
    {
        solve();
    }
    
    return 0;
}
accuracy: 1
time_ms: 350
memory_kb: 3320
final_rank: 4

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

using ll = long long;

bool is_end = false;

//   2
// 3 * 1
//   0
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};


void solve()
{
    int H, W; cin >> H >> W;
    if (H == 0 && W == 0)
    {
        is_end = true;
        return;
    }
    
    vector<vector<int>> pair_to_num(H, vector<int>(W));
    vector<pair<int, int>> num_to_pair(H * W);
    for (int i = 0; i < H; ++i)
    {
        for (int j = 0; j < W; ++j)
        {
            pair_to_num[i][j] = i * W + j;
            num_to_pair[i * W + j] = {i, j};
        }
    }
    
    vector<vector<int>> graph(H * W, vector<int>(4, -1));
    for (int i = 0; i < 2 * H - 1; ++i)
    {
        if (i % 2 == 0)
        {
            for (int j = 0; j < W - 1; ++j)
            {
                int left = pair_to_num[i/2][j];
                int right = pair_to_num[i/2][j+1];
                
                int c; cin >> c;
                if (c == 0)
                {
                    graph[left][1] = right;
                    graph[right][3] = left;
                }
                
            }
        }
        else
        {
            for (int j = 0; j < W; ++j)
            {
                int up = pair_to_num[i/2][j];
                int down = pair_to_num[i/2+1][j];
                
                int c; cin >> c;
                if (c == 0)
                {
                    graph[up][0] = down;
                    graph[down][2] = up;
                }
                
            }
        }
        
    }
    
    int S = 0, T = H * W - 1;
    const int INF = 1e9;
    vector<vector<int>> dist_to_T(H * W, vector<int>(4, INF));
    
    vector<int> dist(H * W, INF);
    queue<int> que;
    
    for (int x = 0; x < H; ++x)
    {
        for (int y = 0; y < W; ++y)
        {
            for (int dir = 0; dir < 4; ++dir)
            {
                int v = pair_to_num[x][y];
                int nv = graph[v][dir];
                
                if (nv == -1) continue;
                
                {
                    dist.assign(H * W, INF);
                    assert((int)que.size() == 0);
                    
                    que.push(v);
                    dist[v] = 0;
                    
                    while (!que.empty())
                    {
                        int u = que.front();
                        que.pop();
                        
                        for (auto nu : graph[u])
                        {
                            if (nu == -1) continue;
                            if (dist[nu] < INF) continue;
                            if (u == v && nu == nv) continue;
                            dist[nu] = dist[u] + 1;
                            que.push(nu);
                        }
                    }
                    
                    
                    dist_to_T[v][dir] = dist[T];
                    
                    // cout << x << " " << y << " " << dir << " " << dist_to_T[v][dir] << endl;
                }
                
            }
        }
    }
    
    // for (int dir = 0; dir < 4; ++dir)
    // {
    //     cout << dir << " " << dist_to_T[0][dir] << endl;
    // }
    
    int ok = INF, ng = 0;
    while (abs(ok - ng) > 1)
    {
        int mid = (ok + ng) / 2;
        
        {
            dist.assign(H * W, INF);
            assert((int)que.size() == 0);
            
            que.push(S);
            dist[S] = 0;
            
            while (!que.empty())
            {
                int v = que.front();
                que.pop();
                
                for (int dir = 0; dir < 4; ++dir)
                {
                    int nv = graph[v][dir];
                    if (nv == -1) continue;
                    if (dist[nv] < INF) continue;
                    
                    int sum = dist[v] + dist_to_T[v][dir];
                    if (sum <= mid)
                    {
                        // if (v == 0 && dir == 0) cout << sum << " " << mid << endl;
                        dist[nv] = dist[v] + 1;
                        que.push(nv);
                    }
                }
            }
            
            if (dist[T] < INF) ok = mid;
            else ng = mid;
        }
        
    }
    
    if (ok == INF) ok = -1;
    cout << ok << endl;
    
    
    return;
}

int main()
{
    while (!is_end)
    {
        solve();
    }
    
    return 0;
}
accuracy: 1
time_ms: 330
memory_kb: 3496
final_rank: 5

code_snippet: #include<iostream>
#include<string>
#include<vector>
#include<math.h>
#include<iomanip>
#include<algorithm>
#include<set>
#include<map>
#include<queue>
#include<stack>
// #include<atcoder/all>

using namespace std;
// using namespace atcoder;
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;

int main(){
	while (true){
		int h, w;
		cin >> h >> w;
		if (h == 0 && w == 0) {
			break;
		}
		vector<vector<pii>> graph(h * w, vector<pii>(0));
		vector<pii> edges(0);
		int cnt = 0;
		for (size_t i = 0; i < h; i++)
		{
			for (size_t j = 0; j < w - 1; j++)
			{
				int x;
				cin >> x;
				if (x == 0) {
					edges.push_back(pii(i * w + j, i * w + (j + 1)));
					graph[i * w + j].push_back(pii(i * w + (j + 1), cnt));
					edges.push_back(pii(i * w + (j + 1), i * w + j));
					graph[i * w + (j + 1)].push_back(pii((i * w + j), cnt));
					cnt++;
				}
			}
			if (i == h - 1) continue;
			for (size_t j = 0; j < w; j++)
			{
				int x;
				cin >> x;
				if (x == 0) {
					edges.push_back(pii(i * w + j, (i + 1) * w + j));
					graph[i * w + j].push_back(pii((i + 1) * w + j, cnt));
					edges.push_back(pii((i + 1) * w + j, i * w + j));
					graph[(i + 1) * w + j].push_back(pii(i * w + j, cnt));
					cnt++;
				}
			}
		}
		vector<vector<int>> dist_rem(cnt, vector<int>(h * w, 1000000000));
		for (size_t i = 0; i < cnt; i++)
		{
			dist_rem[i][h * w - 1] = 0;
		}
		
		for (size_t i = 0; i < cnt; i++)
		{
			queue<int> q2;
			q2.push(h * w - 1);
			while (q2.size() > 0) {
				int cur = q2.front();
				q2.pop();
				for (auto _next: graph[cur]) {
					if (_next.second == i) continue;
					int next = _next.first;
					if (dist_rem[i][next] <= dist_rem[i][cur] + 1) continue;
					dist_rem[i][next] = dist_rem[i][cur] + 1;
					q2.push(next);
				}
			}
		}
		int ok = 1000000000;
		int ng = 0;
		while (ok - ng > 1) {
			int mid = ng + (ok - ng) / 2;
			
			vector<int> dist_real(h * w, 1000000000);
			dist_real[0] = 0;
			queue<int> q3;
			q3.push(0);
			while (q3.size() > 0) {
				int cur = q3.front();
				q3.pop();
				for (auto _next: graph[cur]) {
					int next = _next.first;
					int next_edge = _next.second;
					if (dist_real[next] <= dist_real[cur] + 1) continue;
					if (dist_real[cur] + dist_rem[next_edge][cur] > mid) continue;
					dist_real[next] = dist_real[cur] + 1;
					q3.push(next);
				}
			}

			if (dist_real[h * w - 1] <= mid) ok = mid;
			else ng = mid;
		}
		if (ok == 1000000000) {
			cout << -1 << endl;
		}
		else {
			cout << ok << endl;
		}
	}
}
accuracy: 1
time_ms: 120
memory_kb: 9352
final_rank: 14

code_snippet: #include<iostream>
#include<string>
#include<vector>
#include<math.h>
#include<iomanip>
#include<algorithm>
#include<set>
#include<map>
#include<queue>
#include<stack>
// #include<atcoder/all>

using namespace std;
// using namespace atcoder;
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;

int main(){
	while (true){
		int h, w;
		cin >> h >> w;
		if (h == 0 && w == 0) {
			break;
		}
		vector<vector<pii>> graph(h * w, vector<pii>(0));
		vector<pii> edges(0);
		int cnt = 0;
		for (size_t i = 0; i < h; i++)
		{
			for (size_t j = 0; j < w - 1; j++)
			{
				int x;
				cin >> x;
				if (x == 0) {
					edges.push_back(pii(i * w + j, i * w + (j + 1)));
					graph[i * w + j].push_back(pii(i * w + (j + 1), cnt));
					edges.push_back(pii(i * w + (j + 1), i * w + j));
					graph[i * w + (j + 1)].push_back(pii((i * w + j), cnt));
					cnt++;
				}
			}
			if (i == h - 1) continue;
			for (size_t j = 0; j < w; j++)
			{
				int x;
				cin >> x;
				if (x == 0) {
					edges.push_back(pii(i * w + j, (i + 1) * w + j));
					graph[i * w + j].push_back(pii((i + 1) * w + j, cnt));
					edges.push_back(pii((i + 1) * w + j, i * w + j));
					graph[(i + 1) * w + j].push_back(pii(i * w + j, cnt));
					cnt++;
				}
			}
		}
		vector<int> dist(h * w, 1000000000);
		dist[0] = 0;
		vector<vector<int>> dist_rem(cnt, vector<int>(h * w, 1000000000));
		for (size_t i = 0; i < cnt; i++)
		{
			dist_rem[i][h * w - 1] = 0;
		}
		
		queue<int> q;
		q.push(0);
		while (q.size() > 0) {
			int cur = q.front();
			q.pop();
			for (auto _next: graph[cur]) {
				int next = _next.first;
				if (dist[next] <= dist[cur] + 1) continue;
				dist[next] = dist[cur] + 1;
				q.push(next);
			}
		}
		for (size_t i = 0; i < cnt; i++)
		{
			queue<int> q2;
			q2.push(h * w - 1);
			while (q2.size() > 0) {
				int cur = q2.front();
				q2.pop();
				for (auto _next: graph[cur]) {
					if (_next.second == i) continue;
					int next = _next.first;
					if (dist_rem[i][next] <= dist_rem[i][cur] + 1) continue;
					dist_rem[i][next] = dist_rem[i][cur] + 1;
					q2.push(next);
				}
			}
		}
		int ok = 1000000000;
		int ng = 0;
		while (ok - ng > 1) {
			int mid = ng + (ok - ng) / 2;
			
			vector<int> dist_real(h * w, 1000000000);
			dist_real[0] = 0;
			queue<int> q3;
			q3.push(0);
			while (q3.size() > 0) {
				int cur = q3.front();
				q3.pop();
				for (auto _next: graph[cur]) {
					int next = _next.first;
					int next_edge = _next.second;
					if (dist_real[next] <= dist_real[cur] + 1) continue;
					if (dist_real[cur] + dist_rem[next_edge][cur] > mid) continue;
					dist_real[next] = dist_real[cur] + 1;
					q3.push(next);
				}
			}

			if (dist_real[h * w - 1] <= mid) ok = mid;
			else ng = mid;
		}
		if (ok == 1000000000) {
			cout << -1 << endl;
		}
		else {
			cout << ok << endl;
		}
	}
}
accuracy: 1
time_ms: 100
memory_kb: 9304
final_rank: 13

code_snippet: #line 1 "a.cpp"
// cSpell:disable
/*	author:  Kite_kuma
	created: 2022.11.22 14:09:21 */

#line 2 "SPJ-Library/graph/graph.hpp"
#include <algorithm>
#include <cassert>
#include <deque>
#include <iostream>
#include <limits>
#include <queue>
#include <tuple>
#include <vector>

template <class cost_type = long long>
class graph {
   public:
	struct edge {
	   public:
		int from, to;
		cost_type cost;
		int id;
		edge() = default;
		edge(int from_, int to_, cost_type cost_ = 1, int id_ = -1) : from(from_), to(to_), cost(cost_), id(id_) {}
		bool operator<(const edge &a) const { return cost < a.cost; }
		bool operator>(const edge &a) const { return cost > a.cost; }
		friend std::ostream &operator<<(std::ostream &s, const edge &a) {
			s << '(' << a.from << " -> " << a.to << "), cost: " << a.cost << ", id: " << a.id;
			return s;
		}
	};

   private:
	std::vector<std::vector<edge>> edges;
	int next_edge_id = 0;

   public:
	inline const std::vector<edge> &operator[](int k) const { return edges[k]; }
	inline std::vector<edge> &operator[](int k) { return edges[k]; }

	int size() const { return int(edges.size()); }
	void resize(const int n) { edges.resize(n); }
	int edge_count() const { return next_edge_id; }

	friend std::ostream &operator<<(std::ostream &s, const graph<cost_type> &g) {
		s << "{\n";
		for(const auto &adj : g.edges)
			for(const auto &ed : adj) s << '\t' << ed << '\n';
		s << "}";
		return s;
	}

	graph() = default;
	graph(int n) : edges(n) {}
	graph(int n, int e, bool weight = 0, bool directed = 0, int idx = 1) : edges(n) { input(e, weight, directed, idx); }
	static constexpr cost_type INF = std::numeric_limits<cost_type>::max() / 3;

	void input(int e = -1, bool weight = false, bool directed = false, int idx = 1) {
		if(e == -1) e = size() - 1;
		while(e--) {
			int u, v;
			std::cin >> u >> v;
			cost_type cost = 1;
			if(weight) std::cin >> cost;
			add_edge(u, v, cost, directed, idx);
		}
	}

	inline int add_edge(int u, int v, cost_type cost = 1, bool directed = false, int idx = 0) {
		u -= idx, v -= idx;
		edges[u].emplace_back(u, v, cost, next_edge_id);
		if(!directed && u != v) edges[v].emplace_back(v, u, cost, next_edge_id);
		return next_edge_id++;
	}

	// Ο(V+E)
	std::vector<cost_type> bfs(int s) const {
		std::vector<cost_type> dist(size(), INF);
		std::queue<int> que;
		dist[s] = 0;
		que.push(s);
		while(!que.empty()) {
			int v = que.front();
			que.pop();
			for(auto &e : edges[v]) {
				if(dist[e.to] != INF) continue;
				dist[e.to] = dist[v] + e.cost;
				que.push(e.to);
			}
		}
		return dist;
	}

	// Ο(V+E)
	// constraint: cost of each edge is zero or x (>= 0)
	std::vector<cost_type> zero_one_bfs(int s) const {
		std::vector<cost_type> dist(size(), INF);
		std::deque<int> deq;
		dist[s] = 0;
		deq.push_back(s);
		while(!deq.empty()) {
			int v = deq.front();
			deq.pop_front();
			for(auto &e : edges[v]) {
				if(dist[e.to] > dist[v] + e.cost) {
					dist[e.to] = dist[v] + e.cost;
					e.cost ? deq.push_back(e.to) : deq.push_front(e.to);
				}
			}
		}
		return dist;
	}

	// Ο((E+V) lg E)
	// unreachable: INF
	std::vector<cost_type> dijkstra(int s) const {
		std::vector<cost_type> dist(size(), INF);
		const auto compare = [](const std::pair<cost_type, int> &a, const std::pair<cost_type, int> &b) { return a.first > b.first; };
		std::priority_queue<std::pair<cost_type, int>, std::vector<std::pair<cost_type, int>>, decltype(compare)> que{compare};
		dist[s] = 0;
		que.emplace(0, s);
		while(!que.empty()) {
			std::pair<cost_type, int> p = que.top();
			que.pop();
			int v = p.second;
			if(dist[v] < p.first) continue;
			for(auto &e : edges[v]) {
				if(dist[e.to] > dist[v] + e.cost) {
					dist[e.to] = dist[v] + e.cost;
					que.emplace(dist[e.to], e.to);
				}
			}
		}
		return dist;
	}

	// Ο(VE)
	// unreachable: INF
	// reachable via negative cycle: -INF
	std::vector<cost_type> bellman_ford(int s) const {
		int n = size();
		std::vector<cost_type> res(n, INF);
		res[s] = 0;
		for(int loop = 0; loop < n - 1; loop++) {
			for(int v = 0; v < n; v++) {
				if(res[v] == INF) continue;
				for(auto &e : edges[v]) {
					res[e.to] = std::min(res[e.to], res[v] + e.cost);
				}
			}
		}
		std::queue<int> que;
		std::vector<int> chk(n);
		for(int v = 0; v < n; v++) {
			if(res[v] == INF) continue;
			for(auto &e : edges[v]) {
				if(res[e.to] > res[v] + e.cost and !chk[e.to]) {
					que.push(e.to);
					chk[e.to] = 1;
				}
			}
		}
		while(!que.empty()) {
			int now = que.front();
			que.pop();
			for(auto &e : edges[now]) {
				if(!chk[e.to]) {
					chk[e.to] = 1;
					que.push(e.to);
				}
			}
		}
		for(int i = 0; i < n; i++)
			if(chk[i]) res[i] = -INF;
		return res;
	}

	// Ο(V^3)
	std::vector<std::vector<cost_type>> warshall_floyd() const {
		const int n = size();
		std::vector<std::vector<cost_type>> dist(n, std::vector<cost_type>(n, INF));
		for(int i = 0; i < n; i++) dist[i][i] = 0;
		for(int i = 0; i < n; i++)
			for(auto &e : edges[i]) dist[i][e.to] = std::min(dist[i][e.to], e.cost);
		for(int k = 0; k < n; k++)
			for(int i = 0; i < n; i++) {
				if(dist[i][k] == INF) continue;
				for(int j = 0; j < n; j++) {
					if(dist[k][j] == INF) continue;
					dist[i][j] = std::min(dist[i][j], dist[i][k] + dist[k][j]);
				}
			}
		return dist;
	}

	// Ο(V) (using DFS)
	// if a cycle exists, return {}
	std::vector<int> topological_sort() const {
		std::vector<int> res;
		std::vector<int> used(size(), 0);
		bool not_DAG = false;
		auto dfs = [&](auto self, int k) -> void {
			if(not_DAG) return;
			if(used[k]) {
				if(used[k] == 1) not_DAG = true;
				return;
			}
			used[k] = 1;
			for(auto &e : edges[k]) self(self, e.to);
			used[k] = 2;
			res.push_back(k);
		};
		for(int i = 0; i < size(); i++) dfs(dfs, i);
		if(not_DAG) return std::vector<int>{};
		std::reverse(res.begin(), res.end());
		return res;
	}

	bool is_dag() const { return !topological_sort().empty(); }

	// Ο(V)
	// array of the distance to the most distant vertex
	// constraint: the graph is a tree
	std::vector<cost_type> height() const {
		auto vec1 = bfs(0);
		int v1 = -1, v2 = -1;
		cost_type dia = -1;
		for(int i = 0; i < int(size()); i++)
			if(dia < vec1[i]) dia = vec1[i], v1 = i;
		vec1 = bfs(v1);
		dia = -1;
		for(int i = 0; i < int(size()); i++)
			if(dia < vec1[i]) dia = vec1[i], v2 = i;
		auto vec2 = bfs(v2);
		for(int i = 0; i < int(size()); i++) {
			if(vec1[i] < vec2[i]) vec1[i] = vec2[i];
		}
		return vec1;
	}

	// O(V+E)
	// vector<(int)(0 or 1)>
	// if it is not bipartite, return {}
	std::vector<int> bipartite_grouping() const {
		std::vector<int> colors(size(), -1);
		auto dfs = [&](auto self, int now, int col) -> bool {
			colors[now] = col;
			for(auto &e : edges[now]) {
				if(col == colors[e.to]) return false;
				if(colors[e.to] == -1 and !self(self, e.to, !col)) return false;
			}
			return true;
		};
		for(int i = 0; i < int(size()); i++)
			if(colors[i] == -1 and !dfs(dfs, i, 0)) return std::vector<int>{};
		return colors;
	}

	bool is_bipartite() const { return !bipartite_grouping().empty(); }

	// Ο(V+E)
	// (v1, v2, diameter)
	std::tuple<int, int, cost_type> diameter() {
		std::vector<cost_type> dist = bfs(0);
		auto it = std::max_element(dist.begin(), dist.end());
		const int v = int(it - dist.begin());
		dist = bfs(v);
		it = std::max_element(dist.begin(), dist.end());
		return std::make_tuple(v, int(it - dist.begin()), *it);
	}

	// Ο(V+E)
	std::vector<int> subtree_size(const int root) {
		const int n = size();
		std::vector<int> ret(n, 1);
		auto dfs = [&](auto self, int now, int p = -1) -> void {
			for(const auto &e : (*this)[now]) {
				if(e.to == p) continue;
				self(self, e.to, now);
				ret[now] += ret[e.to];
			}
		};
		dfs(dfs, root);
		return ret;
	}

	// Ο(ElgE)
	cost_type prim() const {
		cost_type res = 0;
		std::priority_queue<edge, std::vector<edge>, std::greater<edge>> que;
		for(auto &e : edges[0]) que.push(e);
		std::vector<int> chk(size());
		chk[0] = 1;
		int cnt = 1;
		while(cnt < size()) {
			auto e = que.top();
			que.pop();
			if(chk[e.to]) continue;
			cnt++;
			res += e.cost;
			chk[e.to] = 1;
			for(auto &e2 : edges[e.to]) que.push(e2);
		}
		return res;
	}

	// Ο(ElgE)
	cost_type kruskal() const {
		std::vector<std::tuple<int, int, cost_type>> eds;
		for(const auto &adj : edges)
			for(const auto &ed : adj) eds.emplace_back(ed.from, ed.to, ed.cost);
		std::sort(eds.begin(), eds.end(), [](const std::tuple<int, int, cost_type> &a, const std::tuple<int, int, cost_type> &b) {
			return std::get<2>(a) < std::get<2>(b);
		});
		std::vector<int> uf_data(size(), -1);
		auto root = [&uf_data](auto self, int x) -> int {
			if(uf_data[x] < 0) return x;
			return uf_data[x] = self(self, uf_data[x]);
		};
		auto unite = [&uf_data, &root](int u, int v) -> bool {
			u = root(root, u), v = root(root, v);
			if(u == v) return false;
			if(uf_data[u] > uf_data[v]) std::swap(u, v);
			uf_data[u] += uf_data[v];
			uf_data[v] = u;
			return true;
		};
		cost_type ret = 0;
		for(auto &e : eds)
			if(unite(std::get<0>(e), std::get<1>(e))) ret += std::get<2>(e);
		return ret;
	}

	// O(V)
	std::vector<int> centroid() const {
		std::vector<int> centroid, sz(size());
		auto dfs = [&](auto self, int now, int per) -> void {
			sz[now] = 1;
			bool is_centroid = true;
			for(auto &e : edges[now]) {
				if(e.to != per) {
					self(self, e.to, now);
					sz[now] += sz[e.to];
					if(sz[e.to] > size() / 2) is_centroid = false;
				}
			}
			if(size() - sz[now] > size() / 2) is_centroid = false;
			if(is_centroid) centroid.push_back(now);
		};
		dfs(dfs, 0, -1);
		return centroid;
	}

	// O(V+E)
	// bridge: (s, t)  (s < t);
	std::pair<std::vector<std::pair<int, int>>, std::vector<int>> bridges_and_articulations() const {
		std::vector<int> order(size(), -1), low(size()), articulation;
		int order_next = 0;
		std::vector<std::pair<int, int>> bridge;
		auto dfs = [&](auto self, int now, int par = -1) -> void {
			low[now] = order[now] = order_next++;
			bool is_articulation = false;
			int cnt = 0;
			for(auto &ed : edges[now]) {
				int &nxt = ed.to;
				if(nxt == par) continue;
				if(order[nxt] == -1) {
					cnt++;
					self(self, nxt, now);
					if(order[now] < low[nxt]) bridge.push_back(std::minmax(now, nxt));
					if(order[now] <= low[nxt]) is_articulation = true;
					low[now] = std::min(low[now], low[nxt]);
				} else if(order[now] > order[nxt]) {
					low[now] = std::min(low[now], order[nxt]);
				}
			}
			if(par == -1 and cnt < 2) is_articulation = false;
			if(is_articulation) articulation.push_back(now);
			return;
		};
		for(int i = 0; i < (int)size(); i++)
			if(order[i] == -1) dfs(dfs, i);
		return std::make_pair(bridge, articulation);
	}

	// Ο(V+E)
	// directed graph from root to leaf
	graph root_to_leaf(int root = 0) const {
		graph res(size());
		std::vector<int> chk(size(), 0);
		chk[root] = 1;
		auto dfs = [&](auto self, int now) -> void {
			for(auto &e : edges[now]) {
				if(chk[e.to] == 1) continue;
				chk[e.to] = 1;
				res.add_edge(now, e.to, e.cost, 1, 0);
				self(self, e.to);
			}
		};
		dfs(dfs, root);
		return res;
	}

	// Ο(V+E)
	// directed graph from leaf to root
	graph leaf_to_root(int root = 0) const {
		graph res(size());
		std::vector<int> chk(size(), 0);
		chk[root] = 1;
		auto dfs = [&](auto self, int now) -> void {
			for(auto &e : edges[now]) {
				if(chk[e.to] == 1) continue;
				chk[e.to] = 1;
				res.add_edge(e.to, now, e.cost, 1, 0);
				self(self, e.to);
			}
		};
		dfs(dfs, root);
		return res;
	}
};
#line 2 "SPJ-Library/template/kuma.hpp"

#line 2 "SPJ-Library/template/basic_func.hpp"

#line 7 "SPJ-Library/template/basic_func.hpp"

template <class T0, class T1, class T2>
inline bool in_range(T0 x, T1 lef, T2 rig) {
	return ((lef <= x) && (x < rig));
}

template <class T>
inline bool chmin(T &a, T b) {
	if(a > b) {
		a = b;
		return true;
	}
	return false;
}
template <class T>
inline bool chmax(T &a, T b) {
	if(a < b) {
		a = b;
		return true;
	}
	return false;
}

void Yes(bool flag = true) { std::cout << (flag ? "Yes" : "No") << '\n'; }
void YES(bool flag = true) { std::cout << (flag ? "YES" : "NO") << '\n'; }

template <class T>
void drop(T answer) {
	std::cout << answer << '\n';
	exit(0);
}

template <class T>
void vout(std::vector<T> const &v, bool vertically = 0) {
	if(vertically) {
		for(auto const &a : v) {
			std::cout << a << '\n';
		}
		return;
	}
	for(auto it = v.begin(); it != v.end(); it++) {
		std::cout << (*it);
		if(it != v.end() - 1) {
			std::cout << ' ';
		}
	}
	std::cout << '\n';
	return;
}

inline void print() { std::cout << '\n'; }
template <class T>
inline void print(const T &x) {
	std::cout << x << '\n';
	return;
}
template <typename Head, typename... Tail>
void print(const Head &H, const Tail &... T) {
	std::cout << H << " ";
	print(T...);
}

template <class T>
void add(std::vector<T> &v, T value) {
	for(auto &a : v) a += value;
	return;
}

template <class T>
T greatest_lower_multiple(T x, T d) {
	if(d == 0) return 0;
	if(d < 0) d *= -1;
	T y = x % d;
	if(y < 0) y += d;
	return x - y;
}

template <class T>
T least_upper_multiple(T x, T d) {
	return -greatest_lower_multiple(-x, d);
}

// ceil(a / b);
template <class T>
T dup(T a, T b) {
	assert(b);
	if(b < 0) {
		a *= -1;
		b *= -1;
	}
	return least_upper_multiple(a, b) / b;
}

long long pow_ll(long long a, long long n) {
	assert(n >= 0LL);
	if(n == 0) return 1LL;
	if(a == 0) return 0LL;
	if(a == 1) return 1LL;
	if(a == -1) return (n & 1LL) ? -1LL : 1LL;
	long long res = 1;
	while(n > 1LL) {
		if(n & 1LL) res *= a;
		a *= a;
		n >>= 1;
	}
	return res * a;
}

long long modpow(long long a, long long n, long long mod) {	 // a^n mod
	assert(n >= 0 && mod);
	if(mod == 1) return 0LL;
	long long res = 1;
	a %= mod;
	while(n > 0) {
		if(n & 1) res = res * a % mod;
		a = a * a % mod;
		n >>= 1;
	}
	return res < 0 ? res + mod : res;
}

// return x which satisfies a * x % mod == gcd(a, mod)
// not (mod | a)
long long modinv(long long a, const long long mod) {
	long long b = mod, u = 1, v = 0;
	while(b) {
		long long t = a / b;
		a -= t * b;
		std::swap(a, b);
		u -= t * v;
		std::swap(u, v);
	}
	u %= mod;
	if(u < 0) u += mod;
	return u;
}

template <class T>
int lb(const std::vector<T> &a, const T x) {
	return (int)std::distance(a.begin(), std::lower_bound(a.begin(), a.end(), x));
}
template <class T>
int ub(const std::vector<T> &a, const T x) {
	return (int)std::distance(a.begin(), std::upper_bound(a.begin(), a.end(), x));
}
template <class T>
void unq_sort(std::vector<T> &a) {
	std::sort(a.begin(), a.end());
	a.erase(std::unique(a.begin(), a.end()), a.end());
}
template <class T>
std::vector<int> press(const std::vector<T> &a) {
	std::vector<T> vec = a;
	unq_sort(vec);
	std::vector<int> ret;
	for(const auto &v : a) ret.push_back(lb(vec, v));
	return ret;
}
#line 1 "SPJ-Library/template/header.hpp"
#include <bits/stdc++.h>
#line 2 "SPJ-Library/template/io.hpp"

#line 4 "SPJ-Library/template/io.hpp"

#line 8 "SPJ-Library/template/debug.hpp"

#line 3 "SPJ-Library/template/constants.hpp"

constexpr int inf = 1000'000'000;
constexpr long long INF = 1'000'000'000'000'000'000LL;
constexpr int mod_1000000007 = 1000000007;
constexpr int mod_998244353 = 998244353;
const long double pi = acosl(-1.);
constexpr int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
constexpr int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};
#line 10 "SPJ-Library/template/debug.hpp"

namespace viewer {

template <typename T, typename U>
void view(const std::pair<T, U> &p);

template <class T0, class T1, class T2>
void view(const std::tuple<T0, T1, T2> &p);

template <class T0, class T1, class T2, class T3>
void view(const std::tuple<T0, T1, T2, T3> &p);

void view(const long long &e);

void view(const int &e);

template <typename T>
void view(const T &e);

template <typename T>
void view(const std::set<T> &s);

template <typename T>
void view(const std::unordered_set<T> &s);

template <typename T>
void view(const std::multiset<T> &s);

template <typename T>
void view(const std::unordered_multiset<T> &s);

template <typename T>
void view(const std::vector<T> &v);

template <typename T, std::size_t ary_size>
void view(const std::array<T, ary_size> &v);

template <typename T>
void view(const std::vector<std::vector<T>> &vv);

template <typename T, typename U>
void view(const std::vector<std::pair<T, U>> &v);

template <class T0, class T1, class T2>
void view(const std::vector<std::tuple<T0, T1, T2>> &v);

template <class T0, class T1, class T2, class T3>
void view(const std::vector<std::tuple<T0, T1, T2, T3>> &v);

template <typename map_type>
void view_map_container(const map_type &m);

template <typename T, typename U>
void view(const std::map<T, U> &m);

template <typename T, typename U>
void view(const std::unordered_map<T, U> &m);

template <typename container_type>
void view_container(const container_type &c, bool vertically = false) {
	typename container_type::const_iterator begin = c.begin();
	const typename container_type::const_iterator end = c.end();
	if(vertically) {
		std::cerr << "{\n";
		while(begin != end) {
			std::cerr << '\t';
			view(*(begin++));
			if(begin != end) std::cerr << ',';
			std::cerr << '\n';
		}
		std::cerr << '}';
		return;
	}
	std::cerr << "{ ";
	while(begin != end) {
		view(*(begin++));
		if(begin != end) std::cerr << ',';
		std::cerr << ' ';
	}
	std::cerr << '}';
}

template <typename T, typename U>
void view(const std::pair<T, U> &p) {
	std::cerr << '(';
	view(p.first);
	std::cerr << ", ";
	view(p.second);
	std::cerr << ')';
}

template <class T0, class T1, class T2>
void view(const std::tuple<T0, T1, T2> &p) {
	std::cerr << '(';
	view(std::get<0>(p));
	std::cerr << ", ";
	view(std::get<1>(p));
	std::cerr << ", ";
	view(std::get<2>(p));
	std::cerr << ')';
}

template <class T0, class T1, class T2, class T3>
void view(const std::tuple<T0, T1, T2, T3> &p) {
	std::cerr << '(';
	view(std::get<0>(p));
	std::cerr << ", ";
	view(std::get<1>(p));
	std::cerr << ", ";
	view(std::get<2>(p));
	std::cerr << ", ";
	view(std::get<3>(p));
	std::cerr << ')';
}

void view(const long long &e) {
	if(e == INF)
		std::cerr << "INF";
	else if(e == -INF)
		std::cerr << "-INF";
	else
		std::cerr << e;
}

void view(const int &e) {
	if(e == inf)
		std::cerr << "inf";
	else if(e == -inf)
		std::cerr << "-inf";
	else
		std::cerr << e;
}

template <typename T>
void view(const T &e) {
	std::cerr << e;
}

template <typename T>
void view(const std::set<T> &s) {
	view_container(s);
}

template <typename T>
void view(const std::unordered_set<T> &s) {
	view_container(s);
}

template <typename T>
void view(const std::multiset<T> &s) {
	view_container(s);
}

template <typename T>
void view(const std::unordered_multiset<T> &s) {
	view_container(s);
}

template <typename T>
void view(const std::vector<T> &v) {
	view_container(v);
}

template <typename T, std::size_t ary_size>
void view(const std::array<T, ary_size> &v) {
	view_container(v);
}

template <typename T>
void view(const std::vector<std::vector<T>> &vv) {
	view_container(vv, true);
}

template <typename T, typename U>
void view(const std::vector<std::pair<T, U>> &v) {
	view_container(v, true);
}

template <class T0, class T1, class T2>
void view(const std::vector<std::tuple<T0, T1, T2>> &v) {
	view_container(v, true);
}

template <class T0, class T1, class T2, class T3>
void view(const std::vector<std::tuple<T0, T1, T2, T3>> &v) {
	view_container(v, true);
}

template <typename map_type>
void view_map_container(const map_type &m) {
	std::cerr << "{\n";
	for(typename map_type::const_iterator it = m.begin(); it != m.end(); it++) {
		std::cerr << "\t[";
		view(it->first);
		std::cerr << "] : ";
		view(it->second);
		std::cerr << '\n';
	}
	std::cerr << "}";
}

template <typename T, typename U>
void view(const std::map<T, U> &m) {
	view_map_container(m);
}

template <typename T, typename U>
void view(const std::unordered_map<T, U> &m) {
	view_map_container(m);
}

}  // namespace viewer

// when compiling : g++ foo.cpp -DLOCAL
#ifdef LOCAL
void debug_out() {}
template <typename T>
void debug_out(const T &x) {
	viewer::view(x);
}
template <typename Head, typename... Tail>
void debug_out(const Head &H, const Tail &... T) {
	viewer::view(H);
	std::cerr << ", ";
	debug_out(T...);
}
#define debug(...)                                                \
	do {                                                          \
		std::cerr << __LINE__ << " [" << #__VA_ARGS__ << "] : ["; \
		debug_out(__VA_ARGS__);                                   \
		std::cerr << "]\n";                                       \
	} while(0)
#else
#define debug(...) (void(0))
#endif
#line 2 "SPJ-Library/template/scanner.hpp"

#line 6 "SPJ-Library/template/scanner.hpp"

namespace scanner {
template <class T>
void scan(T &a) {
	std::cin >> a;
}

template <class T, class L>
void scan(std::pair<T, L> &p) {
	scan(p.first);
	scan(p.second);
}

template <class T0, class T1, class T2>
void scan(std::tuple<T0, T1, T2> &p) {
	T0 t0;
	T1 t1;
	T2 t2;
	scan(t0);
	scan(t1);
	scan(t2);
	p = std::make_tuple(t0, t1, t2);
}

template <class T0, class T1, class T2, class T3>
void scan(std::tuple<T0, T1, T2, T3> &p) {
	T0 t0;
	T1 t1;
	T2 t2;
	T3 t3;
	scan(t0);
	scan(t1);
	scan(t2);
	scan(t3);
	p = std::make_tuple(t0, t1, t2, t3);
}

template <class T>
void scan(std::vector<T> &a) {
	for(auto &i : a) scan(i);
}

void INPUT() {}
template <class Head, class... Tail>
void INPUT(Head &head, Tail &... tail) {
	scan(head);
	INPUT(tail...);
}
}  // namespace scanner
#line 7 "SPJ-Library/template/io.hpp"

#define VEC(type, name, size) \
	vector<type> name(size);  \
	scanner::INPUT(name)
#define VVEC(type, name, h, w)                     \
	vector<vector<type>> name(h, vector<type>(w)); \
	scanner::INPUT(name)
#define INT(...)     \
	int __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define LL(...)            \
	long long __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define STR(...)        \
	string __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define CHR(...)      \
	char __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define DBL(...)        \
	double __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define LD(...)              \
	long double __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define TPL3(type0, type1, type2, name)   \
	std::tuple<type0, type1, type2> name; \
	scanner::INPUT(name);
#define TPL4(type0, type1, type2, type3, name)   \
	std::tuple<type0, type1, type2, type3> name; \
	scanner::INPUT(name);

template <typename T1, typename T2>
std::istream &operator>>(std::istream &is, std::pair<T1, T2> &p) {
	is >> p.first >> p.second;
	return is;
}

template <typename T1, typename T2>
std::ostream &operator<<(std::ostream &os, const std::pair<T1, T2> &p) {
	os << p.first << ' ' << p.second;
	return os;
}

struct fast_io {
	fast_io() {
		std::ios::sync_with_stdio(false);
		std::cin.tie(nullptr);
		std::cout << std::fixed << std::setprecision(15);
		srand((unsigned)time(NULL));
	}
} fast_io_;
#line 2 "SPJ-Library/template/macros.hpp"

#define foa(s, v) for(auto &s : v)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
#define pcnt(n) __builtin_popcountll((long long)n)

#define REPname(a, b, c, d, e, ...) e
#define rep(...) REPname(__VA_ARGS__, REP3, REP2, REP1, REP0)(__VA_ARGS__)
#define REP0(x) for(int Counter_in_rep_macro = 0; Counter_in_rep_macro < (x); ++Counter_in_rep_macro)
#define REP1(i, x) for(int i = 0; i < (x); ++i)
#define REP2(i, l, r) for(int i = (l); i < (r); ++i)
#define REP3(i, l, r, c) for(int i = (l); i < (r); i += (c))
#define DREPname(a, b, c, d, e, ...) e
#define drep(...) DREPname(__VA_ARGS__, DREP3, DREP2, DREP1)(__VA_ARGS__)
#define DREP1(i, x) for(int i = (x)-1; i >= 0; --i)
#define DREP2(i, l, r) for(int i = (r)-1; i >= (l); --i)
#define DREP3(i, l, r, c) for(int i = (r)-1; i >= (l); i -= (c))

using ll = long long;
using ld = long double;
using ull = unsigned long long;
using vi = std::vector<int>;
using vvi = std::vector<std::vector<int>>;
using vvvi = std::vector<std::vector<std::vector<int>>>;
using vll = std::vector<ll>;
using vvll = std::vector<vll>;
using vvvll = std::vector<vvll>;
template <class T = ll>
using V = std::vector<T>;
template <class T = ll>
using VV = V<V<T>>;
template <class T = ll>
using VVV = V<V<V<T>>>;
template <class T = ll>
using pqup = std::priority_queue<T, std::vector<T>, std::greater<T>>;
template <class T = ll>
using pqdn = std::priority_queue<T>;
#line 7 "SPJ-Library/template/kuma.hpp"

using namespace std;
#line 7 "a.cpp"

int solve(int h, int w) {
	vector<vector<int>> room_id(h, vi(w));
	int rid = 0;
	foa(row, room_id) foa(c, row) c = rid++;
	vector<vector<int>> door_id(rid, vi(4, -1));
	auto adj_id = door_id;
	int did = 0;
	auto move_yoko = [&](int row_id) -> void {
		rep(j, w - 1) {
			int c;
			cin >> c;
			int left = room_id[row_id][j];
			int right = room_id[row_id][j + 1];

			if(c == 0) {
				door_id[left][0] = did;
				door_id[right][2] = did++;
				adj_id[left][0] = right;
				adj_id[right][2] = left;
			}
		}
		return;
	};
	auto move_tate = [&](int upper_row_id) -> void {
		rep(j, w) {
			int c;
			cin >> c;
			int up = room_id[upper_row_id][j];
			int down = room_id[upper_row_id + 1][j];

			if(c == 0) {
				door_id[up][3] = did;
				door_id[down][1] = did++;
				adj_id[up][3] = down;
				adj_id[down][1] = up;
			}
		}
		return;
	};
	rep(r, h - 1) {
		move_yoko(r);
		move_tate(r);
	}
	move_yoko(h - 1);

	// debug(room_id);
	// debug(door_id);
	// debug(rid, did);

	vector<vector<int>> to_goal;
	rep(broken_id, did) {
		graph<int> g(rid);
		rep(i, h) rep(j, w) {
			const int from = room_id[i][j];
			// debug(i, j, from);
			rep(dir, 4) {
				int pass = door_id[from][dir];
				// debug(dir, pass);
				if(pass != -1 && pass != broken_id) {
					const int to = adj_id[from][dir];
					// debug(from, to);
					assert(in_range(from, 0, rid) && in_range(to, 0, rid));
					g.add_edge(from, to, 1, true, 0);
				}
			}
		}
		to_goal.push_back(g.bfs(room_id[h - 1][w - 1]));
		if(to_goal.back().front() == g.INF) return -1;
	}

	// debug(to_goal);
	// exit(0);

	vector<int> move_grid = {1, -w, -1, w};

	auto judge = [&](int card) -> bool {
		vector<int> dist(rid, inf);
		dist.front() = 0;
		queue<int> q;
		q.push(0);
		while(q.size()) {
			int now = q.front();
			q.pop();
			if(now == room_id.back().back()) return true;
			rep(dir, 4) {
				int nxt_door = door_id[now][dir];
				if(nxt_door == -1) continue;
				int nxt_room = now + move_grid[dir];
				if(to_goal[nxt_door][now] + dist[now] <= card && chmin(dist[nxt_room], dist[now] + 1)) {
					q.push(nxt_room);
				}
			}
		}
		return false;
	};

	int ok = rid * 10;
	int ng = 0;
	while(abs(ok - ng) > 1) {
		int med = (ok + ng) / 2;

		if(judge(med)) {
			ok = med;
		} else {
			ng = med;
		}
	}

	return ok;
}
int main() {
	int h, w;
	while(cin >> h >> w && h + w) {
		cout << solve(h, w) << '\n';
	}
	return 0;
}
accuracy: 1
time_ms: 1120
memory_kb: 9492
final_rank: 18

code_snippet: #pragma region Macros
#if defined(noimi) && defined(_GLIBCXX_DEBUG) && defined(_GLIBCXX_DEBUG_PEDANTIC)
// #pragma comment(linker, "/stack:200000000")
#include <stdc++.h>
#pragma GCC optimize("O3")
#else
#pragma GCC optimize("Ofast")
// #pragma GCC optimize("unroll-loops")
// #pragma GCC target("popcnt")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,fma,abm,mmx,avx,avx2,tune=native")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,fma,abm,mmx,avx,avx2")
// #pragma GCC target("avx2")
// #include <bits/stdc++.h>
#include <bits/stdc++.h>
#endif
#include <cstdint>
#include <immintrin.h>
#include <variant>

#ifdef noimi
#define oj_local(a, b) b
#else
#define oj_local(a, b) a
#endif

#define LOCAL if(oj_local(0, 1))
#define OJ if(oj_local(1, 0))

using namespace std;
using ll = long long;
using ull = unsigned long long int;
using i128 = __int128_t;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using ld = long double;
template <typename T> using vc = vector<T>;
template <typename T> using vvc = vector<vc<T>>;
template <typename T> using vvvc = vector<vvc<T>>;
using vi = vc<int>;
using vl = vc<ll>;
using vpi = vc<pii>;
using vpl = vc<pll>;
template <class T> using pq = priority_queue<T>;
template <class T> using pqg = priority_queue<T, vector<T>, greater<T>>;
template <typename T> int si(const T &x) { return x.size(); }
template <class T, class S> inline bool chmax(T &a, const S &b) { return (a < b ? a = b, 1 : 0); }
template <class T, class S> inline bool chmin(T &a, const S &b) { return (a > b ? a = b, 1 : 0); }
vi iota(int n) {
    vi a(n);
    return iota(a.begin(), a.end(), 0), a;
}
template <typename T> vi iota(const vector<T> &a, bool greater = false) {
    vi res(a.size());
    iota(res.begin(), res.end(), 0);
    sort(res.begin(), res.end(), [&](int i, int j) {
        if(greater) return a[i] > a[j];
        return a[i] < a[j];
    });
    return res;
}

// macros
#define overload5(a, b, c, d, e, name, ...) name
#define overload4(a, b, c, d, name, ...) name
#define endl '\n'
#define REP0(n) for(ll jidlsjf = 0; jidlsjf < n; ++jidlsjf)
#define REP1(i, n) for(ll i = 0; i < (n); ++i)
#define REP2(i, a, b) for(ll i = (a); i < (b); ++i)
#define REP3(i, a, b, c) for(ll i = (a); i < (b); i += (c))
#define rep(...) overload4(__VA_ARGS__, REP3, REP2, REP1, REP0)(__VA_ARGS__)
#define per0(n) for(int jidlsjf = 0; jidlsjf < (n); ++jidlsjf)
#define per1(i, n) for(ll i = (n)-1; i >= 0; --i)
#define per2(i, a, b) for(ll i = (a)-1; i >= b; --i)
#define per3(i, a, b, c) for(ll i = (a)-1; i >= (b); i -= (c))
#define per(...) overload4(__VA_ARGS__, per3, per2, per1, per0)(__VA_ARGS__)
#define fore0(a) rep(a.size())
#define fore1(i, a) for(auto &&i : a)
#define fore2(a, b, v) for(auto &&[a, b] : v)
#define fore3(a, b, c, v) for(auto &&[a, b, c] : v)
#define fore4(a, b, c, d, v) for(auto &&[a, b, c, d] : v)
#define fore(...) overload5(__VA_ARGS__, fore4, fore3, fore2, fore1, fore0)(__VA_ARGS__)
#define fi first
#define se second
#define pb push_back
#define ppb pop_back
#define ppf pop_front
#define eb emplace_back
#define drop(s) cout << #s << endl, exit(0)
#define si(c) (int)(c).size()
#define lb(c, x) distance((c).begin(), lower_bound(all(c), (x)))
#define ub(c, x) distance((c).begin(), upper_bound(all(c), (x)))
#define rng(v, l, r) v.begin() + l, v.begin() + r
#define all(c) begin(c), end(c)
#define rall(c) rbegin(c), rend(c)
#define SORT(v) sort(all(v))
#define REV(v) reverse(all(v))
#define UNIQUE(x) SORT(x), x.erase(unique(all(x)), x.end())
template <typename T = ll, typename S> T SUM(const S &v) { return accumulate(all(v), T(0)); }
#define MIN(v) *min_element(all(v))
#define MAX(v) *max_element(all(v))
#define overload2(_1, _2, name, ...) name
#define vec(type, name, ...) vector<type> name(__VA_ARGS__)
#define vv(type, name, h, ...) vector<vector<type>> name(h, vector<type>(__VA_ARGS__))
#define vvv(type, name, h, w, ...) vector<vector<vector<type>>> name(h, vector<vector<type>>(w, vector<type>(__VA_ARGS__)))
#define vvvv(type, name, a, b, c, ...)                                                                                                                         \
    vector<vector<vector<vector<type>>>> name(a, vector<vector<vector<type>>>(b, vector<vector<type>>(c, vector<type>(__VA_ARGS__))))
constexpr pii dx4[4] = {pii{1, 0}, pii{0, 1}, pii{-1, 0}, pii{0, -1}};
constexpr pii dx8[8] = {{1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}};

namespace yesno_impl {
const string YESNO[2] = {"NO", "YES"};
const string YesNo[2] = {"No", "Yes"};
const string yesno[2] = {"no", "yes"};
const string firstsecond[2] = {"second", "first"};
const string FirstSecond[2] = {"Second", "First"};
const string possiblestr[2] = {"impossible", "possible"};
void YES(bool t = 1) { cout << YESNO[t] << endl; }
void NO(bool t = 1) { YES(!t); }
void Yes(bool t = 1) { cout << YesNo[t] << endl; }
void No(bool t = 1) { Yes(!t); }
void yes(bool t = 1) { cout << yesno[t] << endl; }
void no(bool t = 1) { yes(!t); }
void first(bool t = 1) { cout << firstsecond[t] << endl; }
void First(bool t = 1) { cout << FirstSecond[t] << endl; }
void possible(bool t = 1) { cout << possiblestr[t] << endl; }
}; // namespace yesno_impl
using namespace yesno_impl;

#define INT(...)                                                                                                                                               \
    int __VA_ARGS__;                                                                                                                                           \
    IN(__VA_ARGS__)
#define LL(...)                                                                                                                                                \
    ll __VA_ARGS__;                                                                                                                                            \
    IN(__VA_ARGS__)
#define STR(...)                                                                                                                                               \
    string __VA_ARGS__;                                                                                                                                        \
    IN(__VA_ARGS__)
#define CHR(...)                                                                                                                                               \
    char __VA_ARGS__;                                                                                                                                          \
    IN(__VA_ARGS__)
#define DBL(...)                                                                                                                                               \
    double __VA_ARGS__;                                                                                                                                        \
    IN(__VA_ARGS__)
#define VEC(type, name, size)                                                                                                                                  \
    vector<type> name(size);                                                                                                                                   \
    IN(name)
#define VEC2(type, name1, name2, size)                                                                                                                         \
    vector<type> name1(size), name2(size);                                                                                                                     \
    for(int i = 0; i < size; i++) IN(name1[i], name2[i])
#define VEC3(type, name1, name2, name3, size)                                                                                                                  \
    vector<type> name1(size), name2(size), name3(size);                                                                                                        \
    for(int i = 0; i < size; i++) IN(name1[i], name2[i], name3[i])
#define VEC4(type, name1, name2, name3, name4, size)                                                                                                           \
    vector<type> name1(size), name2(size), name3(size), name4(size);                                                                                           \
    for(int i = 0; i < size; i++) IN(name1[i], name2[i], name3[i], name4[i]);
#define VV(type, name, h, w)                                                                                                                                   \
    vector<vector<type>> name(h, vector<type>(w));                                                                                                             \
    IN(name)
int scan() { return getchar(); }
void scan(int &a) { cin >> a; }
void scan(long long &a) { cin >> a; }
void scan(char &a) { cin >> a; }
void scan(double &a) { cin >> a; }
void scan(string &a) { cin >> a; }
template <class T, class S> void scan(pair<T, S> &p) { scan(p.first), scan(p.second); }
template <class T> void scan(vector<T> &);
template <class T> void scan(vector<T> &a) {
    for(auto &i : a) scan(i);
}
template <class T> void scan(T &a) { cin >> a; }
void IN() {}
template <class Head, class... Tail> void IN(Head &head, Tail &...tail) {
    scan(head);
    IN(tail...);
}

template <typename T, typename S> T ceil(T x, S y) {
    assert(y);
    return (y < 0 ? ceil(-x, -y) : (x > 0 ? (x + y - 1) / y : x / y));
}

template <typename T, typename S> T floor(T x, S y) {
    assert(y);
    return (y < 0 ? floor(-x, -y) : (x > 0 ? x / y : x / y - (x % y == 0 ? 0 : 1)));
}
template <class T> T POW(T x, int n) {
    T res = 1;
    for(; n; n >>= 1, x *= x)
        if(n & 1) res *= x;
    return res;
}
template <class T, class S> T POW(T x, S n, const ll &mod) {
    T res = 1;
    x %= mod;
    for(; n; n >>= 1, x = x * x % mod)
        if(n & 1) res = res * x % mod;
    return res;
}
vector<pll> factor(ll x) {
    vector<pll> ans;
    for(ll i = 2; i * i <= x; i++)
        if(x % i == 0) {
            ans.push_back({i, 1});
            while((x /= i) % i == 0) ans.back().second++;
        }
    if(x != 1) ans.push_back({x, 1});
    return ans;
}
template <class T> vector<T> divisor(T x) {
    vector<T> ans;
    for(T i = 1; i * i <= x; i++)
        if(x % i == 0) {
            ans.pb(i);
            if(i * i != x) ans.pb(x / i);
        }
    return ans;
}
template <typename T> void zip(vector<T> &x) {
    vector<T> y = x;
    UNIQUE(y);
    for(int i = 0; i < x.size(); ++i) { x[i] = lb(y, x[i]); }
}
template <class S> void fold_in(vector<S> &v) {}
template <typename Head, typename... Tail, class S> void fold_in(vector<S> &v, Head &&a, Tail &&...tail) {
    for(auto e : a) v.emplace_back(e);
    fold_in(v, tail...);
}
template <class S> void renumber(vector<S> &v) {}
template <typename Head, typename... Tail, class S> void renumber(vector<S> &v, Head &&a, Tail &&...tail) {
    for(auto &&e : a) e = lb(v, e);
    renumber(v, tail...);
}
template <class S, class... Args> vector<S> zip(vector<S> &head, Args &&...args) {
    vector<S> v;
    fold_in(v, head, args...);
    sort(all(v)), v.erase(unique(all(v)), v.end());
    renumber(v, head, args...);
    return v;
}
template <typename T> vector<T> RUI(const vector<T> &v) {
    vector<T> res(v.size() + 1);
    for(int i = 0; i < v.size(); i++) res[i + 1] = res[i] + v[i];
    return res;
}
// 反時計周りに 90 度回転
template <typename T> void rot(vector<vector<T>> &v) {
    if(empty(v)) return;
    int n = v.size(), m = v[0].size();
    vector res(m, vector<T>(n));
    rep(i, n) rep(j, m) res[m - 1 - j][i] = v[i][j];
    v.swap(res);
}
// x in [l, r)
template <class T, class S> bool inc(const T &x, const S &l, const S &r) { return l <= x and x < r; }

// 便利関数
constexpr ll ten(int n) { return n == 0 ? 1 : ten(n - 1) * 10; }
constexpr ll tri(ll n) { return n * (n + 1) / 2; }
// l + ... + r
constexpr ll tri(ll l, ll r) { return (l + r) * (r - l + 1) / 2; }
ll max(int x, ll y) { return max((ll)x, y); }
ll max(ll x, int y) { return max(x, (ll)y); }
int min(int x, ll y) { return min((ll)x, y); }
int min(ll x, int y) { return min(x, (ll)y); }
// bit 演算系
ll pow2(int i) { return 1LL << i; }
int topbit(signed t) { return t == 0 ? -1 : 31 - __builtin_clz(t); }
int topbit(ll t) { return t == 0 ? -1 : 63 - __builtin_clzll(t); }
int lowbit(signed a) { return a == 0 ? 32 : __builtin_ctz(a); }
int lowbit(ll a) { return a == 0 ? 64 : __builtin_ctzll(a); }
// int allbit(int n) { return (1 << n) - 1; }
constexpr ll mask(int n) { return (1LL << n) - 1; }
// int popcount(signed t) { return __builtin_popcount(t); }
// int popcount(ll t) { return __builtin_popcountll(t); }
int popcount(uint64_t t) { return __builtin_popcountll(t); }
static inline uint64_t popcount64(uint64_t x) {
    uint64_t m1 = 0x5555555555555555ll;
    uint64_t m2 = 0x3333333333333333ll;
    uint64_t m4 = 0x0F0F0F0F0F0F0F0Fll;
    uint64_t h01 = 0x0101010101010101ll;

    x -= (x >> 1) & m1;
    x = (x & m2) + ((x >> 2) & m2);
    x = (x + (x >> 4)) & m4;

    return (x * h01) >> 56;
}
bool ispow2(int i) { return i && (i & -i) == i; }

ll rnd(ll l, ll r) { //[l, r)
#ifdef noimi
    static mt19937_64 gen;
#else
    static mt19937_64 gen(chrono::steady_clock::now().time_since_epoch().count());
#endif
    return uniform_int_distribution<ll>(l, r - 1)(gen);
}
ll rnd(ll n) { return rnd(0, n); }

template <class t> void random_shuffle(vc<t> &a) { rep(i, si(a)) swap(a[i], a[rnd(0, i + 1)]); }

int in() {
    int x;
    cin >> x;
    return x;
}
ll lin() {
    unsigned long long x;
    cin >> x;
    return x;
}

template <class T, class S> pair<T, S> operator-(const pair<T, S> &x) { return pair<T, S>(-x.first, -x.second); }
template <class T, class S> pair<T, S> operator-(const pair<T, S> &x, const pair<T, S> &y) { return pair<T, S>(x.fi - y.fi, x.se - y.se); }
template <class T, class S> pair<T, S> operator+(const pair<T, S> &x, const pair<T, S> &y) { return pair<T, S>(x.fi + y.fi, x.se + y.se); }
template <class T> pair<T, T> operator&(const pair<T, T> &l, const pair<T, T> &r) { return pair<T, T>(max(l.fi, r.fi), min(l.se, r.se)); }
template <class T, class S> pair<T, S> operator+=(pair<T, S> &l, const pair<T, S> &r) { return l = l + r; }
template <class T, class S> pair<T, S> operator-=(pair<T, S> &l, const pair<T, S> &r) { return l = l - r; }
template <class T> bool intersect(const pair<T, T> &l, const pair<T, T> &r) { return (l.se < r.se ? r.fi < l.se : l.fi < r.se); }

template <typename T> struct edge {
    int from, to;
    T cost;
    int id;
    edge(int to, T cost) : from(-1), to(to), cost(cost) {}
    edge(int from, int to, T cost) : from(from), to(to), cost(cost) {}
    edge(int from, int to, T cost, int id) : from(from), to(to), cost(cost), id(id) {}
    constexpr bool operator<(const edge<T> &rhs) const noexcept { return cost < rhs.cost; }
    edge &operator=(const int &x) {
        to = x;
        return *this;
    }
    operator int() const { return to; }
    friend ostream operator<<(ostream &os, edge &e) { return os << e.to; }
};
template <typename T> using Edges = vector<edge<T>>;

using Tree = vector<vector<int>>;
using Graph = vector<vector<int>>;
template <class T> using Wgraph = vector<vector<edge<T>>>;
Graph getG(int n, int m = -1, bool directed = false, int margin = 1) {
    Tree res(n);
    if(m == -1) m = n - 1;
    while(m--) {
        int a, b;
        cin >> a >> b;
        a -= margin, b -= margin;
        res[a].emplace_back(b);
        if(!directed) res[b].emplace_back(a);
    }
    return res;
}
Graph getTreeFromPar(int n, int margin = 1) {
    Graph res(n);
    for(int i = 1; i < n; i++) {
        int a;
        cin >> a;
        res[a - margin].emplace_back(i);
    }
    return res;
}
template <class T> Wgraph<T> getWg(int n, int m = -1, bool directed = false, int margin = 1) {
    Wgraph<T> res(n);
    if(m == -1) m = n - 1;
    while(m--) {
        int a, b;
        T c;
        scan(a), scan(b), scan(c);
        a -= margin, b -= margin;
        res[a].emplace_back(b, c);
        if(!directed) res[b].emplace_back(a, c);
    }
    return res;
}
void add(Graph &G, int x, int y) { G[x].eb(y), G[y].eb(x); }
template <class S, class T> void add(Wgraph<S> &G, int x, int y, T c) { G[x].eb(y, c), G[y].eb(x, c); }

#define TEST                                                                                                                                                   \
    INT(testcases);                                                                                                                                            \
    while(testcases--)

istream &operator>>(istream &is, i128 &v) {
    string s;
    is >> s;
    v = 0;
    for(int i = 0; i < (int)s.size(); i++) {
        if(isdigit(s[i])) { v = v * 10 + s[i] - '0'; }
    }
    if(s[0] == '-') { v *= -1; }
    return is;
}

ostream &operator<<(ostream &os, const i128 &v) {
    if(v == 0) { return (os << "0"); }
    i128 num = v;
    if(v < 0) {
        os << '-';
        num = -num;
    }
    string s;
    for(; num > 0; num /= 10) { s.push_back((char)(num % 10) + '0'); }
    reverse(s.begin(), s.end());
    return (os << s);
}
namespace aux {
template <typename T, unsigned N, unsigned L> struct tp {
    static void output(std::ostream &os, const T &v) {
        os << std::get<N>(v) << (&os == &cerr ? ", " : " ");
        tp<T, N + 1, L>::output(os, v);
    }
};
template <typename T, unsigned N> struct tp<T, N, N> {
    static void output(std::ostream &os, const T &v) { os << std::get<N>(v); }
};
} // namespace aux
template <typename... Ts> std::ostream &operator<<(std::ostream &os, const std::tuple<Ts...> &t) {
    if(&os == &cerr) { os << '('; }
    aux::tp<std::tuple<Ts...>, 0, sizeof...(Ts) - 1>::output(os, t);
    if(&os == &cerr) { os << ')'; }
    return os;
}
template <class T, class S> ostream &operator<<(ostream &os, const pair<T, S> &p) {
    if(&os == &cerr) { return os << "(" << p.first << ", " << p.second << ")"; }
    return os << p.first << " " << p.second;
}
template <class Ch, class Tr, class Container> std::basic_ostream<Ch, Tr> &operator<<(std::basic_ostream<Ch, Tr> &os, const Container &x) {
    bool f = true;
    if(&os == &cerr) os << "[";
    for(auto &y : x) {
        if(&os == &cerr)
            os << (f ? "" : ", ") << y;
        else
            os << (f ? "" : " ") << y;
        f = false;
    }
    if(&os == &cerr) os << "]";
    return os;
}

#ifdef noimi
#undef endl
void debug() { cerr << endl; }
void debug(bool) { cerr << endl; }
template <class Head, class... Tail> void debug(bool is_front, Head head, Tail... tail) {
    if(!is_front) cerr << ", ";
    cerr << head;
    debug(false, tail...);
}

#define dump(args...)                                                                                                                                          \
    {                                                                                                                                                          \
        vector<string> _debug = _split(#args, ',');                                                                                                            \
        err(true, begin(_debug), args);                                                                                                                        \
    }

vector<string> _split(const string &s, char c) {
    vector<string> v;
    stringstream ss(s);
    string x;
    while(getline(ss, x, c)) {
        if(empty(v))
            v.eb(x);
        else {
            bool flag = false;
            for(auto [c, d] : {pair('(', ')'), pair('[', ']'), pair('{', '}')}) {
                if(count(all(v.back()), c) != count(all(v.back()), d)) flag = true;
            }
            if(flag)
                v.back() += "," + x;
            else
                v.eb(x);
        }
    }
    return move(v);
}

void err(bool, vector<string>::iterator) { cerr << endl; }
template <typename T, typename... Args> void err(bool is_front, vector<string>::iterator it, T a, Args... args) {
    if(!is_front) cerr << ", ";
    cerr << it->substr((*it)[0] == ' ', (*it).size()) << " = " << a, err(false, ++it, args...);
}

// #define dump(...) cerr << #__VA_ARGS__ << " : ", debug(true, __VA_ARGS__)
#else
#define dump(...) static_cast<void>(0)
#define dbg(...) static_cast<void>(0)
#endif
void OUT() { cout << endl; }
template <class Head, class... Tail> void OUT(const Head &head, const Tail &...tail) {
    cout << head;
    if(sizeof...(tail)) cout << ' ';
    OUT(tail...);
}

template <typename T> static constexpr T inf = numeric_limits<T>::max() / 2;
template <class T, class S> constexpr pair<T, S> inf<pair<T, S>> = {inf<T>, inf<S>};

template <class F> struct REC {
    F f;
    REC(F &&f_) : f(std::forward<F>(f_)) {}
    template <class... Args> auto operator()(Args &&...args) const { return f(*this, std::forward<Args>(args)...); }
};

template <class S> vector<pair<S, int>> runLength(const vector<S> &v) {
    vector<pair<S, int>> res;
    for(auto &e : v) {
        if(res.empty() or res.back().fi != e)
            res.eb(e, 1);
        else
            res.back().se++;
    }
    return res;
}
vector<pair<char, int>> runLength(const string &v) {
    vector<pair<char, int>> res;
    for(auto &e : v) {
        if(res.empty() or res.back().fi != e)
            res.eb(e, 1);
        else
            res.back().se++;
    }
    return res;
}

int toint(const char &c, const char start = 'a') { return c - start; }
int toint(const char &c, const string &chars) { return find(all(chars), c) - begin(chars); }
int alphabets_to_int(const char &c) { return (islower(c) ? c - 'a' : c - 'A' + 26); }
template <typename T> auto toint(const T &v, const char &start = 'a') {
    vector<decltype(toint(v[0]))> ret;
    ret.reserve(v.size());
    for(auto &&e : v) ret.emplace_back(toint(e, start));
    return ret;
}
template <typename T> auto toint(const T &v, const string &start) {
    vector<decltype(toint(v[0]))> ret;
    ret.reserve(v.size());
    for(auto &&e : v) ret.emplace_back(toint(e, start));
    return ret;
}
// a -> 0, A -> 26
template <typename T> auto alphabets_to_int(const T &s) {
    vector<decltype(alphabets_to_int(s[0]))> res;
    res.reserve(s.size());
    for(auto &&e : s) { res.emplace_back(alphabets_to_int(e)); }
    return res;
}

template <class T, class F> T bin_search(T ok, T ng, const F &f) {
    while(abs(ok - ng) > 1) {
        T mid = ok + ng >> 1;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}
template <class T, class F> T bin_search_double(T ok, T ng, const F &f, int iter = 80) {
    while(iter--) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}

struct Setup_io {
    Setup_io() {
        ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
        cout << fixed << setprecision(11);
    }
} setup_io;

#pragma endregion

struct Grid {
    int n, m;
    Grid(int n, int m) : n(n), m(m) {}
    struct GridSquare {
        const int &n, &m;
        int x, y;
        GridSquare(const int &n, const int &m, int x, int y) : x(x), y(y), n(n), m(m) {}
        struct itr {
            const int &n, &m, &x, &y;
            int i;
            itr(const int &n, const int &m, const int &x, const int &y) : n(n), m(m), x(x), y(y), i(0) {
                while(!inc(dx4[i].fi + x, 0, n) or !inc(dx4[i].se + x, 0, m)) { i++; }
            }
            bool operator!=(const itr &) const { return i != 4; }
            void operator++() {
                while(i != 4) {
                    i++;
                    if(inc(dx4[i].fi + x, 0, n) and inc(dx4[i].se + y, 0, m)) break;
                }
            }
            pair<int, int> operator*() const { return pair(x + dx4[i].fi, y + dx4[i].se); }
        };
        itr begin() const { return itr(n, m, x, y); }
        itr end() const { return itr(n, m, x, y); }
    };
    GridSquare get(int x, int y) { return GridSquare(n, m, x, y); }
};

int main() {
    rep(100) {
        INT(h, w);
        if(!h) exit(0);

        Grid G(h, w);

        int E = 1;
        using T = tuple<int, int, int>;
        vvv(T, g, h, w, 0);

        vector<pair<pii, pii>> edges;
        rep(i, h * 2 - 1) {
            if(i & 1) {
                VEC(int, a, w);
                rep(j, w) if(!a[j]) {
                    g[i / 2][j].eb(i / 2 + 1, j, E);
                    g[i / 2 + 1][j].eb(i / 2, j, E);
                    edges.eb(pii(i / 2, j), pii(i / 2 + 1, j));
                    E++;
                }
            } else {
                VEC(int, a, w - 1);
                rep(j, w - 1) {
                    if(!a[j]) {
                        g[i / 2][j].eb(i / 2, j + 1, E);
                        g[i / 2][j + 1].eb(i / 2, j, E);
                        edges.eb(pii(i / 2, j), pii(i / 2, j + 1));
                        E++;
                    }
                }
            }
        }

        vvv(int, d, h, w, E, inf<int>);
        queue<T> q;
        rep(i, 1, E) q.emplace(h - 1, w - 1, i), d[h - 1][w - 1][i] = 0;
        while(!empty(q)) {
            auto [i, j, k] = q.front();
            q.pop();
            fore(ni, nj, nk, g[i][j]) {
                if(nk == k) continue;
                if(chmin(d[ni][nj][k], d[i][j][k] + 1)) q.emplace(ni, nj, k);
            }
        }

        pqg<T> pq;
        pq.emplace(0, h - 1, w - 1);
        d[h - 1][w - 1][0] = 0;
        while(!empty(pq)) {
            auto [c, i, j] = pq.top();
            // dump(c, i, j);
            pq.pop();
            if(d[i][j][0] < c) continue;
            fore(ni, nj, nk, g[i][j]) {
                // dump(ni, nj, nk);
                // dump(d[ni][nj][0], d[i][j][0], d[ni][nj][nk]);
                if(chmin(d[ni][nj][0], max(d[i][j][0] + 1, d[ni][nj][nk]))) pq.emplace(d[ni][nj][0], ni, nj);
            }
        }

        int res = d[0][0][0];
        if(res >= inf<int>)
            OUT(-1);
        else
            OUT(res);
    }
}
accuracy: 1
time_ms: 120
memory_kb: 10108
final_rank: 15

code_snippet: #include "bits/stdc++.h"
using namespace std;

#define REP(a, b) for (long long a = 0; a < b; ++a)
#define ll long long
#define ld long double
#define ALL(x) begin(x), end(x)

#define int long long

void solve()
{
  int h, w;
  cin >> h >> w;
  if (h == 0)
    exit(0);
  vector<vector<int>> move_right(h, vector<int>(w, 1));
  vector<vector<int>> move_left(h, vector<int>(w, 1));
  vector<vector<int>> move_up(h, vector<int>(w, 1));
  vector<vector<int>> move_down(h, vector<int>(w, 1));
  REP(i, 2 * h - 1)
  {
    if (i % 2 == 0)
    {
      REP(q, w - 1)
      {
        int a;
        cin >> a;
        if (a == 1)
        {
          move_right[i / 2][q] = 0;
          move_left[i / 2][q + 1] = 0;
        }
      }
    }
    else
    {
      REP(q, w)
      {
        int a;
        cin >> a;
        if (a == 1)
        {
          move_down[i / 2][q] = 0;
          move_up[i / 2 + 1][q] = 0;
        }
      }
    }
  }

  vector<vector<int>> dist(h, vector<int>(w, 0));
  REP(i, h)
  {
    REP(q, w)
    {
      int now_max = 0;
      REP(t, 4)
      {
        int x;
        if (t == 0)
        {
          x = move_down[i][q];
          move_down[i][q] = 0;
        }
        else if (t == 1)
        {
          x = move_up[i][q];
          move_up[i][q] = 0;
        }
        else if (t == 2)
        {
          x = move_right[i][q];
          move_right[i][q] = 0;
        }
        else
        {
          x = move_left[i][q];
          move_left[i][q] = 0;
        }
        vector<vector<int>> moves(h, vector<int>(w, 1e9));
        moves[i][q] = 0;
        queue<pair<int, int>> nexts;
        nexts.push({i, q});
        while (!nexts.empty())
        {
          pair<int, int> now = nexts.front();
          nexts.pop();
          int x = now.first, y = now.second;
          if (x > 0 and move_up[x][y] == 1)
          {
            if (moves[x - 1][y] == 1e9)
            {
              moves[x - 1][y] = moves[x][y] + 1;
              nexts.push({x - 1, y});
            }
          }
          if (x < h - 1 and move_down[x][y] == 1)
          {
            if (moves[x + 1][y] == 1e9)
            {
              moves[x + 1][y] = moves[x][y] + 1;
              nexts.push({x + 1, y});
            }
          }

          if (y > 0 and move_left[x][y] == 1)
          {
            if (moves[x][y - 1] == 1e9)
            {
              moves[x][y - 1] = moves[x][y] + 1;
              nexts.push({x, y - 1});
            }
          }
          if (y < w - 1 and move_right[x][y] == 1)
          {
            if (moves[x][y + 1] == 1e9)
            {
              moves[x][y + 1] = moves[x][y] + 1;
              nexts.push({x, y + 1});
            }
          }
        }

        now_max = max(now_max, moves[h - 1][w - 1]);
        if (t == 0)
        {
          move_down[i][q] = x;
        }
        else if (t == 1)
        {
          move_up[i][q] = x;
        }
        else if (t == 2)
        {
          move_right[i][q] = x;
        }
        else
        {
          move_left[i][q] = x;
        }
      }
      dist[i][q] = now_max;
    }
  }

  int bot = 1e9;
  int top = 0;
  while (bot - top > 1)
  {
    int mid = (bot + top) / 2;
    vector<vector<int>> moves(h, vector<int>(w, 1e9));
    moves[0][0] = 0;
    queue<pair<int, int>> nexts;
    nexts.push({0, 0});
    while (!nexts.empty())
    {
      pair<int, int> now = nexts.front();
      nexts.pop();
      int x = now.first, y = now.second;
      if (x > 0 and move_up[x][y] == 1)
      {
        if (moves[x - 1][y] == 1e9)
        {
          if (moves[x][y] + 1 + dist[x - 1][y] <= mid)
          {
            moves[x - 1][y] = moves[x][y] + 1;
            nexts.push({x - 1, y});
          }
        }
      }
      if (x < h - 1 and move_down[x][y] == 1)
      {
        if (moves[x + 1][y] == 1e9)
        {
          if (moves[x][y] + 1 + dist[x + 1][y] <= mid)
          {
            moves[x + 1][y] = moves[x][y] + 1;
            nexts.push({x + 1, y});
          }
        }
      }

      if (y > 0 and move_left[x][y] == 1)
      {
        if (moves[x][y - 1] == 1e9)
        {
          if (moves[x][y] + 1 + dist[x][y - 1] <= mid)
          {
            moves[x][y - 1] = moves[x][y] + 1;
            nexts.push({x, y - 1});
          }
        }
      }
      if (y < w - 1 and move_right[x][y] == 1)
      {
        if (moves[x][y + 1] == 1e9)
        {
          if (moves[x][y] + 1 + dist[x][y + 1] <= mid)
          {
            moves[x][y + 1] = moves[x][y] + 1;
            nexts.push({x, y + 1});
          }
        }
      }
    }
    if (moves[h - 1][w - 1] != 1e9)
      bot = mid;
    else
      top = mid;
  }
  if (bot == 1e9)
    bot = -1;
  cout << bot << endl;
}

#undef int
int main()
{
  iostream::sync_with_stdio(false);
  cout << fixed << setprecision(100);
  while (true)
  {
    solve();
  }
}
accuracy: 1
time_ms: 740
memory_kb: 3296
final_rank: 11

code_snippet: //https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1178&lang=jp
/* スタート地点からの距離が小さい地点から順に「その地点に隣接するドアが一つ壊れた場合の
最短距離」を決めていく。これを決める際、その地点にたどり着く前の地点の値との max を取れば
順に求めていくことができる。ある種の dp と言えるだろうか。*/

#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for(int i = 0; i < (int)(n); i++)
#define repp(i,k, n) for(int i = (int)(k); i < (int)(n); i++)
#define ALL(a)  (a).begin(),(a).end()
using ll = long long;
using Pi = pair<int, int>;
using Pd = pair<double, double>;
struct Edge{int to; ll w; Edge(int to, ll w) : to(to), w(w) {}};
using Graph = vector<vector<Edge>>;
template<class T> bool chmax(T &a, const T &b) {if (a<b) { a=b; return 1;} return 0;}
template<class T> bool chmin(T &a, const T &b) {if (a>b) { a=b; return 1;} return 0;}
const int di[] = {-1,0,1,0};
const int dj[] = {0,-1,0,1};
const int di8[] = {-1, 0, 1, -1, 1, -1, 0, 1};
const int dj8[] = {1, 1, 1, 0, 0, -1, -1, -1};

constexpr int INF = 1e9 + 7;

template <typename T>
class BrokenDoor
{
public:
    void getField(const int width, const int height)
    {
        width_m = width;
        height_m = height;
        worstShortestLength_m.resize(width_m * height_m, INF);
        graph_m.resize(width_m * height_m);
        rep(i, height_m){
            rep(j, width-1){
                int tmp; cin >> tmp;
                if(!tmp){
                    graph_m[width_m * i + j].push_back(width*i + j + 1);
                    graph_m[width_m * i + j + 1].push_back(width_m * i + j);
                }
            }
            if(i == height_m - 1) break;
            rep(j, width_m){
                int tmp; cin >> tmp;
                if(!tmp){
                    graph_m[width_m * i + j].push_back(width * (i+1) + j);
                    graph_m[width_m * (i+1) + j].push_back(width_m * i + j);
                }
            }
        }
    }

    T dp()
    {
        // とりあえず BFS を実行して各地点への最短距離を求める
        worstShortestLength_m[0] = execBFS(0, 0, make_pair(0, 0));
        // 各地点からゴールまでの最悪の場合の距離を更新していく
        queue<pair<int, int>> posQue;
        posQue.emplace(0, 0);
        worstShortestLength_m[0] = 0;
        while(!posQue.empty()){
            auto cPos = posQue.front().first;
            auto cLength = posQue.front().second;
            posQue.pop();
            for(const auto &to : graph_m[cPos]){
                if(chmin(worstShortestLength_m[to], execBFS(cPos, cLength, make_pair(cPos, to)))){
                    posQue.emplace(to, cLength + 1);
                };
            }
        }
        return worstShortestLength_m[width_m * height_m - 1];
    }
private:
    T execBFS(int start, T startLength, pair<int, int> brokenDoor)
    {
        vector<T> dist_tmp(width_m * height_m);
        // 全ての地点を未到達として初期化
        rep(i, width_m * height_m) dist_tmp[i] = INF;
        queue<int> que;
        que.push(start);
        dist_tmp[start] = startLength;
        while(!que.empty()){
            auto cPos = que.front();
            que.pop();
            for(const auto &to : graph_m[cPos]){
                if(brokenDoor.first == cPos && brokenDoor.second == to) continue;
                if(brokenDoor.first == to && brokenDoor.second == cPos) continue;
                if(chmin(dist_tmp[to], dist_tmp[cPos] + 1)){
                    que.push(to);
                };
            }
        }
        // chmax(worstShortestLength_m[start], dist_tmp[width_m * height_m - 1]);
        return max(worstShortestLength_m[start], dist_tmp[width_m * height_m - 1]);
    }
    int width_m;
    int height_m;
    vector<vector<int>> graph_m;
    //vector<T> dist_m;
    vector<T> worstShortestLength_m;
};

class Solver 
{
public:
    void solve()
    {
        int h, w;
        while(cin >> h >> w && h != 0){
            auto bd = make_unique<BrokenDoor<int>>();
            bd->getField(w, h);
            auto ans = bd->dp();
            if(ans != INF) cout << ans << endl;
            else cout << -1 << endl;
        }
    }
};
int main()
{
    auto solver = make_shared<Solver>();
    solver->solve();
}
accuracy: 1
time_ms: 290
memory_kb: 3412
final_rank: 3

code_snippet: //https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1178&lang=jp
/* スタート地点からの距離が小さい地点から順に「その地点に隣接するドアが一つ壊れた場合の
最短距離」を決めていく。これを決める際、その地点にたどり着く前の地点の値との max を取れば
順に求めていくことができる。ある種の dp と言えるだろうか。*/

#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for(int i = 0; i < (int)(n); i++)
#define repp(i,k, n) for(int i = (int)(k); i < (int)(n); i++)
#define ALL(a)  (a).begin(),(a).end()
using ll = long long;
using Pi = pair<int, int>;
using Pd = pair<double, double>;
struct Edge{int to; ll w; Edge(int to, ll w) : to(to), w(w) {}};
using Graph = vector<vector<Edge>>;
template<class T> bool chmax(T &a, const T &b) {if (a<b) { a=b; return 1;} return 0;}
template<class T> bool chmin(T &a, const T &b) {if (a>b) { a=b; return 1;} return 0;}
const int di[] = {-1,0,1,0};
const int dj[] = {0,-1,0,1};
const int di8[] = {-1, 0, 1, -1, 1, -1, 0, 1};
const int dj8[] = {1, 1, 1, 0, 0, -1, -1, -1};

constexpr int INF = 1e9 + 7;

template <typename T>
class BrokenDoor
{
public:
    void getField(const int width, const int height)
    {
        width_m = width;
        height_m = height;
        worstShortestLength_m.resize(width_m * height_m, INF);
        graph_m.resize(width_m * height_m);
        rep(i, height_m){
            rep(j, width-1){
                int tmp; cin >> tmp;
                if(!tmp){
                    graph_m[width_m * i + j].push_back(width*i + j + 1);
                    graph_m[width_m * i + j + 1].push_back(width_m * i + j);
                }
            }
            if(i == height_m - 1) break;
            rep(j, width_m){
                int tmp; cin >> tmp;
                if(!tmp){
                    graph_m[width_m * i + j].push_back(width * (i+1) + j);
                    graph_m[width_m * (i+1) + j].push_back(width_m * i + j);
                }
            }
        }
    }

    T dp()
    {
        // とりあえず BFS を実行して各地点への最短距離を求める
        worstShortestLength_m[0] = execBFS(0, 0, make_pair(0, 0));
        // 各地点からゴールまでの最悪の場合の距離を更新していく
        queue<pair<int, int>> posQue;
        posQue.emplace(0, 0);
        worstShortestLength_m[0] = 0;
        while(!posQue.empty()){
            auto cPos = posQue.front().first;
            auto cLength = posQue.front().second;
            posQue.pop();
            for(const auto &to : graph_m[cPos]){
                if(chmin(worstShortestLength_m[to], execBFS(cPos, cLength, make_pair(cPos, to)))){
                    posQue.emplace(to, cLength + 1);
                };
            }
        }
        return worstShortestLength_m[width_m * height_m - 1];
    }
private:
    T execBFS(int start, T startLength, pair<int, int> brokenDoor)
    {
        vector<T> dist_tmp(width_m * height_m);
        // 全ての地点を未到達として初期化
        rep(i, width_m * height_m) dist_tmp[i] = INF;
        queue<int> que;
        que.push(start);
        dist_tmp[start] = startLength;
        while(!que.empty()){
            auto cPos = que.front();
            que.pop();
            for(const auto &to : graph_m[cPos]){
                if(brokenDoor.first == cPos && brokenDoor.second == to) continue;
                if(brokenDoor.first == to && brokenDoor.second == cPos) continue;
                if(chmin(dist_tmp[to], dist_tmp[cPos] + 1)){
                    que.push(to);
                };
            }
        }
        // 最初の最短距離の前計算の時は結果を保存
        //if(brokenDoor.first == 0 && brokenDoor.second == 0) dist_m = dist_tmp;
        chmax(worstShortestLength_m[start], dist_tmp[width_m * height_m - 1]);
        return worstShortestLength_m[start];
    }
    int width_m;
    int height_m;
    vector<vector<int>> graph_m;
    //vector<T> dist_m;
    vector<T> worstShortestLength_m;
};

class Solver 
{
public:
    void solve()
    {
        int h, w;
        while(cin >> h >> w && h != 0){
            auto bd = make_unique<BrokenDoor<int>>();
            bd->getField(w, h);
            auto ans = bd->dp();
            if(ans != INF) cout << ans << endl;
            else cout << -1 << endl;
        }
    }
};
int main()
{
    auto solver = make_shared<Solver>();
    solver->solve();
}
accuracy: 1
time_ms: 280
memory_kb: 3384
final_rank: 2

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

// DOWN, RIGHT, UP, LEFT
const int dx[] = {1, 0, -1, 0};
const int dy[] = {0, 1, 0, -1};
const int H_MAX = 33;
const int W_MAX = 33;
const int MOVE_MAX = H_MAX * W_MAX;
const int PROHIBITED = -1;
const int DIST_MAX = 1e5;

int h, w;
int g[H_MAX][W_MAX][4];
int dp[MOVE_MAX][H_MAX][W_MAX];

vector<vector<int>> bfs() {
    vector<vector<int>> dist(h, vector<int>(w, DIST_MAX));
    queue<pair<int, int>> q;
    q.push({h-1, w-1});
    dist[h-1][w-1] = 0;
    while(!q.empty()) {
        auto now = q.front(); q.pop();
        int x = now.first, y = now.second;
        for(int i = 0; i < 4; i++) {
            int nx = x + dx[i], ny = y + dy[i];
            if(g[x][y][i] != PROHIBITED && 
               dist[nx][ny] == DIST_MAX) {
                dist[nx][ny] = dist[x][y] + 1;
                q.push({nx, ny});
            }
        }
    }
    return dist;
}

int solve() {
    for(int i = 0; i < w; i++) {
        g[h-1][i][0] = PROHIBITED;
        g[0][i][2] = PROHIBITED;
    }
    for(int i = 0; i < h; i++) {
        g[i][w-1][1] = PROHIBITED;
        g[i][0][3] = PROHIBITED;
    }
    for(int i = 0; i < h; i++) {
        for(int j = 0; j < w-1; j++) {
            int x; cin >> x;
            g[i][j][1] = g[i][j+1][3] = x == 1 ? PROHIBITED : 0;
        }
        if(i != h-1) {
            for(int j = 0; j < w; j++) {
                int x; cin >> x;
                g[i][j][0] = g[i+1][j][2] =  x == 1 ? PROHIBITED : 0;
            }
        }
    }
    
    for(int i = 0; i < h; i++) {
        for(int j = 0; j < w; j++) {
            for(int k = 0; k < 2; k++) {
                if(g[i][j][k] == PROHIBITED) continue;
                g[i][j][k] = PROHIBITED;
                if(k == 0) g[i+1][j][2] = PROHIBITED;
                else g[i][j+1][3] = PROHIBITED;
                auto &&dist = bfs();
                g[i][j][k] = dist[i][j];
                if(k == 0) g[i+1][j][2] = dist[i+1][j];
                else g[i][j+1][3] = dist[i][j+1];
            }
        }
    }
    
    for(int i = 0; i < h; i++) fill(dp[0][i], dp[0][i] + w, DIST_MAX);
    dp[0][0][0] = 0;
    for(int i = 1; i < MOVE_MAX; i++) {
        for(int j = 0; j < h; j++) fill(dp[i][j], dp[i][j] + w, DIST_MAX);
        for(int j = 0; j < h; j++) {
            for(int k = 0; k < w; k++) {
                for(int l = 0; l < 4; l++) {
                    if(g[j][k][l] != PROHIBITED) {
                        dp[i][j][k] = min(
                             max(g[j+dx[l]][k+dy[l]][l^2] + i-1,
                                 dp[i-1][j+dx[l]][k+dy[l]]),
                             dp[i][j][k]
                        );
                    }
                }
            }
        }
    }
    int ans = DIST_MAX;
    for(int i = 0; i < MOVE_MAX; i++) {
        ans = min(ans, dp[i][h-1][w-1]);
    }
    return ans == DIST_MAX ? -1 : ans;
}

int main() {
    vector<int> ans;
    while(1) {
        cin >> h >> w;
        if(h == 0 && w == 0) break;
        ans.emplace_back(solve());
    }
    for(auto &i : ans) cout << i << endl;
}
accuracy: 1
time_ms: 430
memory_kb: 8120
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=35,INF=1<<29;
vector<int> dh={0,1,0,-1},dw={1,0,-1,0};
bool S[MAX][MAX][4];
int dis[MAX][MAX][4];
int dp[MAX][MAX];

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    while(1){
        int H,W;cin>>H>>W;
        if(H==0) break;
        memset(S,0,sizeof(S));
        for(int i=0;i<H;i++){
            for(int j=0;j<W-1;j++){
                int t;cin>>t;t^=1;
                S[i][j][0]=S[i][j+1][2]=t;
            }
            if(i<H-1){
                for(int j=0;j<W;j++){
                    int t;cin>>t;t^=1;
                    S[i][j][1]=S[i+1][j][3]=t;
                }
            }
        }
        
        for(int i=0;i<H;i++){
            for(int j=0;j<W;j++){
                for(int k=0;k<4;k++){
                    if(S[i][j][k]==0){
                        dis[i][j][k]=-INF;
                        continue;
                    }
                    for(int h=0;h<H;h++) for(int w=0;w<W;w++) dp[h][w]=INF;
                    dp[i][j]=0;
                    queue<pair<int,int>> Q;
                    Q.push(mp(i,j));
                    
                    while(!Q.empty()){
                        auto u=Q.front();Q.pop();
                        for(int d=0;d<4;d++){
                            if(u.fi==i&&u.se==j&&k==d) continue;
                            if(k==0){
                                if(u.fi==i&&u.se==j+1&&d==2) continue;
                            }
                            if(k==1){
                                if(u.fi==i+1&&u.se==j&&d==3) continue;
                            }
                            if(k==2){
                                if(u.fi==i&&u.se==j-1&&d==0) continue;
                            }
                            if(k==3){
                                if(u.fi==i-1&&u.se==j&&d==1) continue;
                            }
                            int toh=u.fi+dh[d],tow=u.se+dw[d];
                            if(toh<0||toh>=H||tow<0||tow>=W||S[u.fi][u.se][d]==0) continue;
                            if(chmin(dp[toh][tow],dp[u.fi][u.se]+1)) Q.push(mp(toh,tow));
                        }
                    }
                    dis[i][j][k]=dp[H-1][W-1];
                }
            }
        }
        
        //for(int i=0;i<H;i++) for(int j=0;j<W;j++) for(int k=0;k<4;k++) cout<<i<<" "<<j<<" "<<k<<" "<<dis[i][j][k]<<endl;
        
        int left=0,right=1805;
        while(right-left>1){
            int mid=(left+right)/2;
            for(int h=0;h<H;h++) for(int w=0;w<W;w++) dp[h][w]=INF;
            dp[0][0]=0;
            queue<pair<int,int>> Q;
            Q.push(mp(0,0));
            while(!Q.empty()){
                auto u=Q.front();Q.pop();
                int d=dp[u.fi][u.se];
                for(int k=0;k<4;k++){
                    if(S[u.fi][u.se][k]==0) continue;
                    int toh=u.fi+dh[k],tow=u.se+dw[k];
                    if(toh<0||toh>=H||tow<0||tow>=W) continue;
                    int ma=-INF;
                    for(int x=0;x<4;x++){
                        if((k^x)==2) continue;
                        chmax(ma,dis[toh][tow][x]);
                    }
                    if(d+1+ma<=mid){
                        if(chmin(dp[toh][tow],d+1)) Q.push(mp(toh,tow));
                    }
                }
            }
            
            if(dp[H-1][W-1]<=mid) right=mid;
            else left=mid;
        }
        
        if(right==1805) cout<<-1<<"\n";
        else cout<<right<<"\n";
    }
}
accuracy: 1
time_ms: 710
memory_kb: 3416
final_rank: 10

code_snippet: //#pragma GCC optimize("O3")
//#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 998244353;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);

ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	ll n;
	modint() :n(0) { ; }
	modint(ll m) :n(m) {
		if (n >= mod)n %= mod;
		else if (n < 0)n = (n % mod + mod) % mod;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 2;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

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

ll gcd(ll a, ll b) {
	while (b) {
		ll r = a % b; a = b; b = r;
	}
	return a;
}

bool b[65][35];
int dist[65][35][35][35];

int val[35][35];
int h, w;
void solve() {
	rep(i, 2 * h - 1) {
		if (i % 2 == 0)rep(j, w - 1)cin >> b[i][j];
		else rep(j, w)cin >> b[i][j];
	}
	auto trans = [&](int i, int j, int d)->P {
		if (d == 0) {
			return { 2 * i + 1,j };
		}
		else if (d == 1) {
			return { 2 * i,j-1 };
		}
		else if (d == 2) {
			return { 2 * i - 1,j };
		}
		else {
			return { 2 * i,j };
		}
	};
	auto isin = [&](int x, int y) {
		return x >= 0 && x < h&& y >= 0 && y < w;
	};
	rep(i, 2 * h - 1) {
		rep(j, w) {
			if (j == w - 1 && i % 2 == 0)continue;
			rep(x, h)rep(y, w) {
				dist[i][j][x][y] = mod;
			}
			dist[i][j][h - 1][w - 1] = 0;
			queue<P> q;
			q.push({ h - 1,w - 1 });
			while (!q.empty()) {
				P p = q.front(); q.pop();
				int cd = dist[i][j][p.first][p.second];
				rep(d, 4) {
					int nx = p.first + dx[d];
					int ny = p.second + dy[d];
					if (!isin(nx, ny))continue;
					P z = trans(p.first, p.second, d);
					if (b[z.first][z.second] || z == P{i, j})continue;
					if (dist[i][j][nx][ny] > cd + 1) {
						dist[i][j][nx][ny] = cd + 1;
						q.push({ nx,ny });
					}
				}
			}
		}
	}
	rep(i, h)rep(j, w) {
		val[i][j] = mod;
	}
	val[h - 1][w - 1] = 0;
	rep(_, h* w) {
		rep(i, h)rep(j, w) {
			rep(d, 4) {
				int nx = i + dx[d];
				int ny = j + dy[d];
				if (!isin(nx, ny))continue;
				P z = trans(i, j, d);
				if (b[z.first][z.second])continue;
				int cost = max(val[nx][ny] + 1, dist[z.first][z.second][i][j]);
				val[i][j] = min(val[i][j], cost);
			}
		}
	}
	/*rep(i, h) {
		rep(j, w) {
			cout << val[i][j] << " ";
		}cout << "\n";
	}*/
	int ans = val[0][0];
	if (ans >= mod)cout << -1 << "\n";
	else cout << ans << "\n";
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(8);
	//init_f();
	//init();
	//int t; cin >> t; rep(i, t)
	while(cin>>h>>w,h)
		solve();
	return 0;
}
accuracy: 1
time_ms: 700
memory_kb: 13340
final_rank: 19

code_snippet: #pragma region Macros
#include <bits/stdc++.h>
using namespace std;
template <class T> inline bool chmax(T &a, T b) {
    if(a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <class T> inline bool chmin(T &a, T b) {
    if(a > b) {
        a = b;
        return 1;
    }
    return 0;
}
#ifdef DEBUG
template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
    os << '{';
    for(int i = 0; i < (int)v.size(); i++) {
        if(i) { os << ','; }
        os << v[i];
    }
    os << '}';
    return os;
}
void debugg() { cerr << endl; }
template <class T, class... Args>
void debugg(const T &x, const Args &... args) {
    cerr << " " << x;
    debugg(args...);
}
#define debug(...)                                                             \
    cerr << __LINE__ << " [" << #__VA_ARGS__ << "]: ", debugg(__VA_ARGS__)
#define dump(x) cerr << __LINE__ << " " << #x << " = " << (x) << endl
#else
#define debug(...) (void(0))
#define dump(x) (void(0))
#endif

struct Setup {
    Setup() {
        cin.tie(0);
        ios::sync_with_stdio(false);
        cout << fixed << setprecision(15);
    }
} __Setup;

using ll = long long;
#define OVERLOAD3(_1, _2, _3, name, ...) name
#define ALL(v) (v).begin(), (v).end()
#define RALL(v) (v).rbegin(), (v).rend()
#define REP1(i, n) for(int i = 0; i < (n); i++)
#define REP2(i, a, b) for(int i = (a); i < int(b); i++)
#define REP(...) OVERLOAD3(__VA_ARGS__, REP2, REP1)(__VA_ARGS__)
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
const int INF = 1 << 29;
const ll LLINF = 1LL << 60;
constexpr int MOD = 1000000007;
constexpr int MOD2 = 998244353;
const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};

void Case(int i) { cout << "Case #" << i << ": "; }
int popcount(int x) { return __builtin_popcount(x); }
ll popcount(ll x) { return __builtin_popcountll(x); }
#pragma endregion Macros

enum directions {
    D, R, U, L
};

bool solve() {
    int H, W;
    cin >> H >> W;
    if(H == 0 and W == 0) return false;
    vector walls(H, vector(W, vector<bool>(4, false)));
    vector<vector<int>> tate(H-1, vector<int>(W));
    REP(i, 2*H-1) {
        if(i % 2 == 0) {
            vector<int> v(W-1);
            REP(j, W-1) cin >> v[j];
            int r = i/2;
            REP(j, W) {
                walls[r][j][R] = (j < W-1 ? v[j] : 1);
                walls[r][j][L] = (j > 0 ? v[j-1] : 1);
            }
        } else {
            REP(j, W) cin >> tate[i/2][j];
        }
    }
    REP(i, H) REP(j, W) {
        walls[i][j][U] = (i > 0 ? tate[i-1][j] : 1);
        walls[i][j][D] = (i < H-1 ? tate[i][j] : 1);
    }

    auto bfs = [&](int sx, int sy, int gx, int gy) -> int {
        vector d(H, vector<int>(W, INF));
        d[sx][sy] = 0;
        queue<pair<int, int>> que;
        que.emplace(sx, sy);
        while(!que.empty()) {
            auto [x, y] = que.front();
            que.pop();
            REP(dir, 4) {
                int nx = x + dx[dir], ny = y + dy[dir];
                if(nx < 0 or nx >= H or ny < 0 or ny >= W) continue;
                bool ok = true;
                if(walls[x][y][dir]) continue;
                if(d[nx][ny] > d[x][y] + 1) {
                    d[nx][ny] = d[x][y] + 1;
                    que.emplace(nx, ny);
                }
            }
        }
        return d[gx][gy];
    };

    vector dist(H, vector(W, vector(4, INF)));

    REP(sx, H) REP(sy, W) REP(dir, 4) {
        if(walls[sx][sy][dir]) continue;
        walls[sx][sy][dir] = 1;
        dist[sx][sy][dir] = bfs(sx, sy, H-1, W-1); 
        walls[sx][sy][dir] = 0;
    }

    int ok = INF, ng = -1;
    while(ok - ng > 1) {
        int mid = (ok + ng) / 2;
        vector d(H, vector<int>(W, INF));
        d[0][0] = 0;
        queue<pair<int, int>> que;
        que.emplace(0, 0);
        while(que.size()) {
            auto [x, y] = que.front();
            que.pop();
            REP(dir, 4) {
                if(dist[x][y][dir] + d[x][y] > mid) continue;
                int nx = x + dx[dir], ny = y + dy[dir];
                if(nx < 0 or nx >= H or ny < 0 or ny >= W) continue;
                if(d[nx][ny] > d[x][y] + 1) {
                    d[nx][ny] = d[x][y] + 1;
                    que.emplace(nx, ny);
                }
            }
        }
        (d[H-1][W-1] < INF ? ok : ng) = mid;
    }
    if(ok == INF) ok = -1;
    cout << ok << '\n';
    
    return true;
}

int main() {
    while(solve());
}
accuracy: 1
time_ms: 480
memory_kb: 3464
final_rank: 9

code_snippet: #pragma GCC tag("avx2")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
using namespace std;
#define DEBUG
#ifdef DEBUG
template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
    os << '{';
    for(int i = 0; i < (int)v.size(); i++) {
        if(i) { os << ','; }
        os << v[i];
    }
    os << '}';
    return os;
}
void debugg() { cerr << endl; }
template <class T, class... Args>
void debugg(const T &x, const Args &... args) {
    cerr << " " << x;
    debugg(args...);
}
#define debug(...)                                                             \
    cerr << __LINE__ << " [" << #__VA_ARGS__ << "]: ", debugg(__VA_ARGS__)
#define dump(x) cerr << __LINE__ << " " << #x << " = " << (x) << endl
#else
#define debug(...) (void(0))
#define dump(x) (void(0))
#endif
using namespace std;
typedef long long ll;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<char> vc;
typedef vector<string> vs;
typedef vector<bool> vb;
typedef vector<double> vd;
typedef pair<ll,ll> P;
typedef pair<int,int> pii;
typedef vector<P> vpl;
typedef tuple<ll,ll,ll> tapu;
#define rep(i,n) for(int i=0; i<(n); i++)
#define REP(i,a,b) for(int i=(a); i<(b); i++)
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
template<typename T1,typename T2> inline bool chmin(T1 &a,T2 b){
	if(a>b){
		a = b; return true;
	}
	else return false;
}
template<typename T1,typename T2> inline bool chmax(T1 &a,T2 b){
	if(a<b){
		a = b; return true;
	}
	else return false;
}
template<typename T> inline void print(T &a){
    int sz = a.size();
    for(auto itr = a.begin(); itr != a.end(); itr++){
		cout << *itr;
        sz--;
        if(sz) cout << " ";
	}
    cout << "\n";
}
template<typename T1,typename T2> inline void print2(T1 a, T2 b){
	cout << a << " " << b << "\n";
}
template<typename T1,typename T2,typename T3> inline void print3(T1 a, T2 b, T3 c){
	cout << a << " " << b << " " << c << "\n";
}
void mark() {cout << "#" << "\n";}
ll pcount(ll x) {return __builtin_popcountll(x);}
//#include <atcoder/maxflow>
//using namespace atcoder;
const int inf = (1<<30)-1;
const ll linf = 1LL<<61;
const int MAX = 5050000;
int dy[8] = {0,1,0,-1,1,-1,-1,1};
int dx[8] = {-1,0,1,0,1,-1,1,-1};
const double pi = acos(-1);
const double eps = 1e-9;
//const int mod = 1e9 + 7;
const int mod = 998244353;

bool in(ll y, ll x, ll h, ll w){
    return 0 <= y && y < h && 0 <= x && x < w;
}

bool in2(ll y, ll x, ll h, ll w, ll dir){
    int Y = y + dy[dir];
    int X = x + dx[dir];
    return 0 <= Y && Y < h && 0 <= X && X < w;
}

int main(){
    while(1){
        int h,w; cin >> h >> w;
        if(!h) break;
        vector<vvl> a(h,vvl(w,vl(4)));
        rep(i,h){
            rep(j,w-1){
                int x; cin >> x;
                a[i][j][2] = x;
                a[i][j+1][0] = x;
            }
            if(i<h-1){
                rep(j,w){
                    int x; cin >> x;
                    a[i][j][1] = x;
                    a[i+1][j][3] = x;
                }
            }
        }
        vvl d2(h,vl(w,inf));
        auto calc = [&](int sy, int sx) -> int {
            rep(i,h) rep(j,w) d2[i][j] = inf;
            d2[sy][sx] = 0;
            queue<P> q;
            q.emplace(sy,sx);
            while(!q.empty()){
                P p = q.front(); q.pop();
                int y = p.first, x = p.second;
                rep(i,4){
                    if(a[y][x][i]) continue;
                    int ny = y + dy[i];
                    int nx = x + dx[i];
                    if(!in(ny,nx,h,w)) continue;
                    if(d2[ny][nx] == inf){
                        d2[ny][nx] = d2[y][x] + 1;
                        q.emplace(ny,nx);
                    }
                }
            }
            return d2[h-1][w-1];
        };
        vector<vvl> precalc(h,vvl(w,vl(4,inf)));
        rep(i,h) rep(j,w) rep(k,4){
            if(a[i][j][k]) continue;
            if(!in2(i,j,h,w,k)) continue;
            a[i][j][k] = 1;
            precalc[i][j][k] = calc(i,j);
            a[i][j][k] = 0;
        }

        int ok = inf, ng = 0;
        while(ok-ng > 1){
            int mid = (ok+ng) / 2;
            vvl d(h,vl(w,inf));
            d[0][0] = 0;
            queue<P> q;
            q.emplace(0,0);
            while(!q.empty()){
                P p = q.front(); q.pop();
                int y = p.first, x = p.second;
                //debug(mid,y,x,precalc[y][x]);
                bool f = true;
                rep(i,4){
                    if(a[y][x][i]) continue;
                    if(!in2(y,x,h,w,i)) continue;
                    if(d[y][x] + precalc[y][x][i] > mid) f = false;
                }
                if(f){
                    rep(i,4){
                        if(a[y][x][i]) continue;
                        int ny = y + dy[i];
                        int nx = x + dx[i];
                        if(!in(ny,nx,h,w)) continue;
                        if(d[ny][nx] == inf){
                            d[ny][nx] = d[y][x] + 1;
                            q.emplace(ny,nx);
                        }
                    }
                }
            }
            if(d[h-1][w-1] <= mid) ok = mid;
            else ng = mid;
        }
        if(ok == inf) ok = -1;
        cout << ok << "\n";
    }
}
accuracy: 1
time_ms: 450
memory_kb: 3608
final_rank: 8

code_snippet: #pragma GCC target("avx")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
#define endl "\n"
#define rep(i,N) for(int i=0;i<N;++i)
template<class T,class E> ostream& operator<<(ostream& os,const pair<T,E>& p){return os<<"("<<p.first<<","<<p.second<<")";}
template<class T> ostream& operator<<(ostream& os,const vector<T>& v){
  os<<"{";bool f=false;
  for(auto& x:v){if(f)os<<",";os<<x;f=true;}
  os<<"}";
  return os;
}
template<class T> ostream& operator<<(ostream& os,const set<T>& v){
  os<<"{";bool f=false;
  for(auto& x:v){if(f)os<<",";os<<x;f=true;}
  os<<"}";
  return os;
}
template<class T> ostream& operator<<(ostream& os,const multiset<T>& v){
  os<<"{";bool f=false;
  for(auto& x:v){if(f)os<<",";os<<x;f=true;}
  os<<"}";
  return os;
}
template<class T,class E> ostream& operator<<(ostream& os,const map<T,E>& v){
  os<<"{";bool f=false;
  for(auto& x:v){if(f)os<<",";os<<x;f=true;}
  os<<"}";
  return os;
}
template<class T> inline bool chmax(T& a,const T b){bool x=a<b;if(x)a=b;return x;}
template<class T> inline bool chmin(T& a,const T b){bool x=a>b;if(x)a=b;return x;}
#ifdef DEBUG
void debugg(){cout<<endl;}
template<class T,class... Args>void debugg(const T& x,const Args&... args){cout<<" "<<x;debugg(args...);}
#define debug(...) cout<<__LINE__<<" ["<<#__VA_ARGS__<<"]:",debugg(__VA_ARGS__)
#else
#define debug(...) (void(0))
#endif
//LDRU
constexpr int dx[4]={1,0,-1,0};
constexpr int dy[4]={0,1,0,-1};
constexpr int inf=1<<20;

int H,W;
//dists[x][y][k]:地点(x,y)で方向kに壁があったときスタート地点から(x,y)に進む最短距離
//distg[x][y][k]:地点(x,y)で方向kに壁があったとき(x,y)からゴール地点に進む最短距離
int dists[30][30][4],distg[30][30][4];
bool moveok[30][30][4];
void input(){
  int i=0,f=0,x;
  rep(tmp,H*2-1){
    if(f){
      //縦方向 (i,j)->(i+1,j)
      rep(j,W){
        cin>>x;
        moveok[i][j][0]=moveok[i+1][j][2]=!x;
      }
    }else{
      //横方向 (i,j)->(i,j+1)
      rep(j,W-1){
        cin>>x;
        moveok[i][j][1]=moveok[i][j+1][3]=!x;
      }
    }
    i+=f;
    f^=1;
  }
  //進んじゃダメ
  rep(i,H)rep(j,W)rep(k,4)if(i+dx[k]<0||i+dx[k]>=H||j+dy[k]<0||j+dy[k]>=W)moveok[i][j][k]=false;
}
//BFS用配列
int dist[30][30];
//dists,distgを計算する
void precalc(){
  rep(i,H)rep(j,W)rep(k,4){
    if(!moveok[i][j][k]){
      dists[i][j][k]=distg[i][j][k]=inf;
      continue;
    }
    moveok[i][j][k]=moveok[i+dx[k]][j+dy[k]][k^2]=false;
    rep(x,H)rep(y,W)dist[x][y]=inf;
    queue<tuple<int,int,int>> que;
    que.emplace(0,i,j);
    while(!que.empty()){
      auto[d,x,y]=que.front();que.pop();
      if(!chmin(dist[x][y],d))continue;
      rep(k,4)if(moveok[x][y][k])que.emplace(d+1,x+dx[k],y+dy[k]);
    }
    dists[i][j][k]=dist[0][0];
    distg[i][j][k]=dist[H-1][W-1];
    moveok[i][j][k]=moveok[i+dx[k]][j+dy[k]][k^2]=true;
  }
}
int main(){
  cin.tie(0);
  ios::sync_with_stdio(false);
  while(1){
    cin>>H>>W;
    if(H+W==0)break;
    rep(i,H)rep(j,W)rep(k,4)dists[i][j][k]=distg[i][j][k]=0;
    input();
    precalc();
    int ok=inf,ng=0;
    while(ok-ng>1){
      int mid=(ok+ng)/2;
      rep(i,H)rep(j,W)dist[i][j]=inf;
      queue<tuple<int,int,int>> que;
      que.emplace(0,0,0);
      while(!que.empty()){
        auto[d,x,y]=que.front();que.pop();
        if(!chmin(dist[x][y],d))continue;
        //ここがポイント、dists[x][y]+distg[x][y]<=midではマズいことになる
        rep(k,4)if(moveok[x][y][k]&&dist[x][y]+distg[x][y][k]<=mid){
          que.emplace(d+1,x+dx[k],y+dy[k]);
        }
      }
      if(dist[H-1][W-1]!=inf)ok=mid;
      else ng=mid;
    }
    if(ok==inf)ok=-1;
    cout<<ok<<endl;
  }
}
accuracy: 1
time_ms: 370
memory_kb: 3396
final_rank: 7

code_snippet: #pragma GCC target("avx")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
#define endl "\n"
#define rep(i,N) for(int i=0;i<N;++i)
template<class T,class E> ostream& operator<<(ostream& os,const pair<T,E>& p){return os<<"("<<p.first<<","<<p.second<<")";}
template<class T> ostream& operator<<(ostream& os,const vector<T>& v){
  os<<"{";bool f=false;
  for(auto& x:v){if(f)os<<",";os<<x;f=true;}
  os<<"}";
  return os;
}
template<class T> ostream& operator<<(ostream& os,const set<T>& v){
  os<<"{";bool f=false;
  for(auto& x:v){if(f)os<<",";os<<x;f=true;}
  os<<"}";
  return os;
}
template<class T> ostream& operator<<(ostream& os,const multiset<T>& v){
  os<<"{";bool f=false;
  for(auto& x:v){if(f)os<<",";os<<x;f=true;}
  os<<"}";
  return os;
}
template<class T,class E> ostream& operator<<(ostream& os,const map<T,E>& v){
  os<<"{";bool f=false;
  for(auto& x:v){if(f)os<<",";os<<x;f=true;}
  os<<"}";
  return os;
}
template<class T> inline bool chmax(T& a,const T b){bool x=a<b;if(x)a=b;return x;}
template<class T> inline bool chmin(T& a,const T b){bool x=a>b;if(x)a=b;return x;}
#ifdef DEBUG
void debugg(){cout<<endl;}
template<class T,class... Args>void debugg(const T& x,const Args&... args){cout<<" "<<x;debugg(args...);}
#define debug(...) cout<<__LINE__<<" ["<<#__VA_ARGS__<<"]:",debugg(__VA_ARGS__)
#else
#define debug(...) (void(0))
#endif
//LDRU
constexpr int dx[4]={1,0,-1,0};
constexpr int dy[4]={0,1,0,-1};
constexpr int inf=1<<20;

int H,W;
int dists[30][30][4],distg[30][30][4];
bool moveok[30][30][4];
void input(){
  int i=0,f=0,x;
  rep(tmp,H*2-1){
    if(f){
      //縦方向 (i,j)->(i+1,j)
      rep(j,W){
        cin>>x;
        moveok[i][j][0]=moveok[i+1][j][2]=!x;
      }
    }else{
      //横方向 (i,j)->(i,j+1)
      rep(j,W-1){
        cin>>x;
        moveok[i][j][1]=moveok[i][j+1][3]=!x;
      }
    }
    i+=f;
    f^=1;
  }
  //進んじゃダメ
  rep(i,H)rep(j,W)rep(k,4)if(i+dx[k]<0||i+dx[k]>=H||j+dy[k]<0||j+dy[k]>=W)moveok[i][j][k]=false;
}
int dist[30][30];
void precalc(){
  rep(i,H)rep(j,W)rep(k,4){
    if(!moveok[i][j][k]){
      dists[i][j][k]=distg[i][j][k]=inf;
      continue;
    }
    moveok[i][j][k]=moveok[i+dx[k]][j+dy[k]][k^2]=false;
    rep(x,H)rep(y,W)dist[x][y]=inf;
    queue<tuple<int,int,int>> que;
    que.emplace(0,i,j);
    while(!que.empty()){
      auto[d,x,y]=que.front();que.pop();
      if(!chmin(dist[x][y],d))continue;
      rep(k,4)if(moveok[x][y][k])que.emplace(d+1,x+dx[k],y+dy[k]);
    }
    dists[i][j][k]=dist[0][0];
    distg[i][j][k]=dist[H-1][W-1];
    moveok[i][j][k]=moveok[i+dx[k]][j+dy[k]][k^2]=true;
  }
}
int main(){
  cin.tie(0);
  ios::sync_with_stdio(false);
  while(1){
    cin>>H>>W;
    if(H+W==0)break;
    rep(i,H)rep(j,W)rep(k,4)dists[i][j][k]=distg[i][j][k]=0;
    input();
    precalc();
    int ok=inf,ng=0;
    while(ok-ng>1){
      int mid=(ok+ng)/2;
      rep(i,H)rep(j,W)dist[i][j]=inf;
      queue<tuple<int,int,int>> que;
      que.emplace(0,0,0);
      while(!que.empty()){
        auto[d,x,y]=que.front();que.pop();
        if(!chmin(dist[x][y],d))continue;
        rep(k,4)if(moveok[x][y][k]&&dist[x][y]+distg[x][y][k]<=mid){
          que.emplace(d+1,x+dx[k],y+dy[k]);
        }
      }
      if(dist[H-1][W-1]!=inf)ok=mid;
      else ng=mid;
    }
    if(ok==inf)ok=-1;
    cout<<ok<<endl;
  }
}
accuracy: 1
time_ms: 370
memory_kb: 3380
final_rank: 6

code_snippet: #include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<cmath>
#include<algorithm>
#include<map>
#include<queue>
#include<deque>
#include<iomanip>
#include<tuple>
#include<cassert>
#include<set>
#include<complex>
#include<numeric>
#include<functional>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long int LL;
typedef pair<int,int> P;
typedef pair<LL,LL> LP;
const int INF=1<<30;
const LL MAX=1e9+7;

void array_show(int *array,int array_n,char middle=' '){
    for(int i=0;i<array_n;i++)printf("%d%c",array[i],(i!=array_n-1?middle:'\n'));
}
void array_show(LL *array,int array_n,char middle=' '){
    for(int i=0;i<array_n;i++)printf("%lld%c",array[i],(i!=array_n-1?middle:'\n'));
}
void array_show(vector<int> &vec_s,int vec_n=-1,char middle=' '){
    if(vec_n==-1)vec_n=vec_s.size();
    for(int i=0;i<vec_n;i++)printf("%d%c",vec_s[i],(i!=vec_n-1?middle:'\n'));
}
void array_show(vector<LL> &vec_s,int vec_n=-1,char middle=' '){
    if(vec_n==-1)vec_n=vec_s.size();
    for(int i=0;i<vec_n;i++)printf("%lld%c",vec_s[i],(i!=vec_n-1?middle:'\n'));
}
template<typename T> ostream& operator<<(ostream& os,const vector<T>& v1){
    int n=v1.size();
    for(int i=0;i<n;i++){
        if(i)os<<" ";
        os<<v1[i];
    }
    return os;
}
template<typename T1,typename T2> ostream& operator<<(ostream& os,const pair<T1,T2>& p){
    os<<p.first<<" "<<p.second;
    return os;
}
template<typename T> istream& operator>>(istream& is,vector<T>& v1){
    int n=v1.size();
    for(int i=0;i<n;i++)is>>v1[i];
    return is;
}
template<typename T1,typename T2> istream& operator>>(istream& is,pair<T1,T2>& p){
    is>>p.first>>p.second;
    return is;
}

namespace sol{
    typedef vector<int> V1;
    typedef vector<V1> V2;
    typedef vector<V2> V3;
    typedef vector<V3> V4;
    typedef tuple<int,int,int> T;
    V2 vw;

    P mid(P a,P b){
        if(a>b)swap(a,b);
        if(a.first==b.first)return {2*a.first,a.second};
        return {2*a.first+1,a.second};
    }
    bool is_wall(P a,P b){
        P pa=mid(a,b);
        return vw[pa.first][pa.second];
    }

    void solve(){
        int n,m;
        int i,j,k;
        int a,b,c;
        int p,q,r;
        while(cin>>n>>m){
            if(n==0)return;
            vw.assign(2*n-1,vector<int>(m));
            for(i=0;i<2*n-1;i++){
                for(j=0;j<m-1+i%2;j++){
                    cin>>vw[i][j];
                }
            }
            V4 dp1(2*n,V3(m,V2(n,V1(m,INF))));
            queue<P> q1;
            for(i=0;i<2*n-1;i++){
                for(j=0;j<m-1+i%2;j++){
                    q1.push({n-1,m-1});
                    for(k=0;!q1.empty();k++){
                        for(p=q1.size();p>0;p--){
                            P pa=q1.front();q1.pop();
                            if(dp1[i][j][pa.first][pa.second]!=INF)continue;
                            dp1[i][j][pa.first][pa.second]=k;
                            for(q=-1;q<=1;q++){
                                for(r=-1;r<=1;r++){
                                    if((q+r+2)%2==0)continue;
                                    int x=pa.first+q,y=pa.second+r;
                                    if(x<0 || y<0 || n<=x || m<=y)continue;
                                    if(is_wall(pa,{x,y}))continue;
                                    if(mid(pa,{x,y})==P(i,j))continue;
                                    q1.push({x,y});
                                }
                            }
                        }
                    }
                }
            }
            V2 dis(n,V1(m,INF));
            priority_queue<T,vector<T>,greater<T>> q2;
            q2.push({0,n-1,m-1});
            while(!q2.empty()){
                tie(a,b,c)=q2.top();q2.pop();
                if(dis[b][c]!=INF || a>=INF)continue;
                dis[b][c]=a;
                for(q=-1;q<=1;q++){
                    for(r=-1;r<=1;r++){
                        if((q+r+2)%2==0)continue;
                        int x=b+q,y=c+r;
                        if(x<0 || y<0 || n<=x || m<=y)continue;
                        if(is_wall({b,c},{x,y}))continue;
                        P pa=mid({b,c},{x,y});
                        int cost=max(a+1,dp1[pa.first][pa.second][x][y]);
                        q2.push({cost,x,y});
                    }
                }
            }
            int s=dis[0][0];
            if(s>=INF)s=-1;
            cout<<s<<endl;
        }
    }
}

int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);
    sol::solve();
}
accuracy: 1
time_ms: 1020
memory_kb: 11212
final_rank: 20