void solution(int N, int M, vector<vector<int>>& graph);
void bfs(Status start, int N, int M, vector<vector<int>>& graph);
bool canGo(int N, int M, Status s);
bool visited[1001][1001][2] = {};
vector<vector<vector<int>>> dist(1001,vector<vector<int>>(1001, vector<int>(2, INT_MAX)));
struct Status
{
int y;
int x;
int crushWall;
};
int main()
{
int N, M;
cin >> N >> M;
vector<vector<int>> graph(N, vector<int>(M));
for (int i = 0; i < N; i++)
for (int j = 0; j < M; j++)
{
char c;
cin >> c;
graph[i][j] = c - '0';
}
solution(N, M, graph);
}
void solution(int N, int M, vector<vector<int>>& graph)
{
Status start;
start.y = 0;
start.x = 0;
start.crushWall = 0;
bfs(start, N, M, graph);
int result = min(dist[N - 1][M - 1][1], dist[N - 1][M - 1][0]);
if (result == INT_MAX)
result = -1;
cout << result;
}
void bfs(Status start,int N, int M, vector<vector<int>>& graph)
{
vector<pair<int,int>> Dirs = { {1, 0} , {0,1} , {-1,0} , {0,-1} };
queue<Status> q;
q.push(start);
visited[start.y][start.x][start.crushWall] = true;
dist[start.y][start.x][start.crushWall] = 1;
while (!q.empty())
{
Status curr = q.front();
q.pop();
for (auto& dir : Dirs)
{
Status next = { curr.y + dir.first, curr.x + dir.second, curr.crushWall };
if (canGo(N, M, next) && !visited[next.y][next.x][next.crushWall])
{
if (graph[next.y][next.x] == 0)
{
q.push(next);
visited[next.y][next.x][next.crushWall] = true;
dist[next.y][next.x][next.crushWall] = dist[curr.y][curr.x][curr.crushWall] + 1;
}
if (graph[next.y][next.x] == 1 && next.crushWall == 0)
{
// 벽부수기!
next.crushWall = 1;
q.push(next);
visited[next.y][next.x][1] = true;
dist[next.y][next.x][1] = dist[curr.y][curr.x][0] + 1;
}
}
}
}
}
bool canGo(int N, int M, Status s)
{
if (s.y < 0 || N <= s.y)
return false;
if (s.x < 0 || M <= s.x)
return false;
return true;
}