#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 1; } return 0; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return 1; } return 0; }
       

template <typename T>
class Grid {
  struct Pos {
    int i, j;
    Pos(int i, int j) : i(i), j(j) {}
  };

  int H, W;
  vector<vector<T>> G;

  vector<int> di8 = {1, 1, 0, -1, -1, -1, 0, 1},
              dj8 = {0, 1, 1, 1, 0, -1, -1, -1};
  vector<int> di4 = {1, 0, -1, 0}, dj4 = {0, 1, 0, -1};

  vector<Pos> neighbor(int i, int j, const vector<int>& dis,
                       const vector<int>& djs) const {
    vector<Pos> res;
    for (int k = 0; k < dis.size(); ++k) {
      if (in(i + dis[k], j + djs[k])) res.emplace_back(i + dis[k], j + djs[k]);
    }
    return res;
  }

 public:
  static bool in(int H, int W, int i, int j) {
    return 0 <= i && i < H && 0 <= j && j < W;
  }

  Grid(int H, int W) : H(H), W(W) { G.resize(H, vector<T>(W)); }
  Grid(int H, int W, T zero) : H(H), W(W) { G.resize(H, vector<T>(W, zero)); }

  vector<T>& operator[](int i) { return G[i]; }

  bool in(int i, int j) const { return (0 <= i && i < H && 0 <= j && j < W); }

  vector<Pos> neighbor8(int i, int j) const { return neighbor(i, j, di8, dj8); }

  vector<Pos> neighbor4(int i, int j) const { return neighbor(i, j, di4, dj4); }

  int to1DIndex(int i, int j) { return i * W + j; }

  Pos to2DIndex(int i) { return Pos(i / W, i % W); }

  void scanFrom(istream& strm) { for (int i = 0; i < (int)(H); ++i) for (int j = 0; j < (int)(W); ++j) strm >> G[i][j]; }

  void outputTo(ostream& strm) {
    for (int i = 0; i < (int)(H); ++i) {
      for (int j = 0; j < (int)(W); ++j) cout << G[i][j];
      strm << endl;
    }
  }
};

template <typename T>
inline istream& operator>>(istream& strm, Grid<T>& g) {
  g.scanFrom(strm);
  return strm;
}

template <typename T>
inline ostream& operator<<(ostream& strm, Grid<T>& g) {
  g.outputTo(strm);
  return strm;
}
       
       

struct Edge {
  int from, to;
  Edge(){};
  Edge(int from, int to) : from(from), to(to) {}

  void scanFrom(std::istream& strm, int base = 1) {
    strm >> from >> to;
    if (base == 1) --from, --to;
  }

  Edge reverse() const { return Edge(to, from); }
};

inline std::istream& operator>>(std::istream& strm, Edge& t) {
  t.scanFrom(strm);
  return strm;
}
       
       

template <typename T>
struct WeightedEdge {
  int from, to;
  T _weight;
  WeightedEdge(){};
  WeightedEdge(int from, int to, T weight)
      : from(from), to(to), _weight(weight) {}

  void scanFrom(std::istream& strm, int base = 1) {
    strm >> from >> to >> _weight;
    if (base == 1) --from, --to;
  }

  T weight() const { return _weight; }

  WeightedEdge reverse() const { return WeightedEdge(to, from, _weight); }
};

template <typename T>
inline std::istream& operator>>(std::istream& strm, WeightedEdge<T>& t) {
  t.scanFrom(strm);
  return strm;
}

template <typename Edge>
class Digraph {
  int _E, _V;
  vector<vector<Edge>> _adjacencyList;

 public:
  int E() const { return _E; }

  int V() const { return _V; }
  int size() const { return _V; }

  Digraph() : _V(0), _E(0){};
  Digraph(int V, int E = 0) : _V(V), _E(E) { _adjacencyList.resize(V); }

  void addEdge(const Edge& e) {
    _adjacencyList[e.from].push_back(e);
    ++_E;
  }

  void addUndirectedEdge(const Edge& e) {
    _adjacencyList[e.from].push_back(e);
    _adjacencyList[e.to].push_back(e.reverse());
    ++_E;
  }

  void addNode() {
    ++_V;
    _adjacencyList.push_back(vector<Edge>());
  }

  void scanFrom(std::istream& strm, int base = 1) {
    if (_V == 0) strm >> _V;
    if (_E == 0) strm >> _E;
    _adjacencyList.resize(_V);
    for (int i = 0; i < _E; ++i) {
      Edge e;
      e.scanFrom(cin, base);
      assert(0 <= e.from < _V);
      assert(0 <= e.to < _V);
      addEdge(e);
    }
  }

  vector<Edge> operator[](int u) const { return _adjacencyList[u]; }
  vector<vector<Edge>>& adjacencyList() { return _adjacencyList; }
};

template <typename Edge>
inline std::istream& operator>>(std::istream& strm, Digraph<Edge>& t) {
  t.scanFrom(strm);
  return strm;
}

class BFSShortestPath {
  const int INF = numeric_limits<int>::max();
  vector<int> _distTo;
  vector<int> prev;

 public:
  BFSShortestPath(const Digraph<Edge>& G, int s)
      : _distTo(G.V(), INF), prev(G.V(), -1) {
    queue<int> q;
    q.push(s);
    _distTo[s] = 0;
    while (!q.empty()) {
      int u = q.front();
      q.pop();
      for (Edge& e : G[u]) {
        if (_distTo[e.to] != INF) continue;
        _distTo[e.to] = _distTo[u] + 1;
        prev[e.to] = u;
        q.push(e.to);
      }
    }
  }

  int distTo(int u) { return _distTo[u]; }

  bool hasPathTo(int u) { return _distTo[u] != INF; }

  vector<int> pathTo(int u) {
    assert(hasPathTo(u));
    vector<int> path;
    while (u != -1) {
      path.push_back(u);
      u = prev[u];
    }
    return path;
  }
};

int solve(int H, int W) {
  int s = 0, t = W * H - 1;

  Grid<int> grid(H, W);
  Digraph<Edge> G(H * W);

  for (int i = 0; i < (int)(H); ++i) {
    for (int j = 0; j < (int)(W - 1); ++j) {
      int w;
      cin >> w;
      if (!w)
        G.addUndirectedEdge(
            Edge(grid.to1DIndex(i, j), grid.to1DIndex(i, j + 1)));
    }

    if (i == H - 1) break;

    for (int j = 0; j < (int)(W); ++j) {
      int w;
      cin >> w;
      if (!w)
        G.addUndirectedEdge(
            Edge(grid.to1DIndex(i, j), grid.to1DIndex(i + 1, j)));
    }
  }

  BFSShortestPath sp(G, s);
  return sp.hasPathTo(t) ? sp.distTo(t) + 1 : 0;
}

int main() {
  int W, H;
  while (true) {
    cin >> W >> H;
    if (W == 0 && H == 0) break;
    cout << solve(H, W) << endl;
  }

  return 0;
}



Measured memory_bytes: 3156