module main; // https://mmxsrup.hatenablog.com/entry/2016/09/20/235927 より // 2次元グリッド、幅優先探索 import std; // 多次元配列をある値で埋める void fill(A, T)(ref A a, T value) if (isArray!A) { alias E = ElementType!A; static if (isArray!E) { foreach (ref e; a) fill(e, value); } else { a[] = value; } } // C++ の tie auto tie(StoreElements...)(ref StoreElements stores) { alias Elements = staticMap!(Unqual, StoreElements); template toPointer(T) { alias toPointer = T*; } struct Holder { alias StoreElementsPtrs = staticMap!(toPointer, StoreElements); StoreElementsPtrs storePtrs; this(ref StoreElements stores) { foreach(i, _; StoreElements) { storePtrs[i] = &stores[i]; } } void opAssign(Tuple!Elements values) { foreach(i, _; Elements) { *storePtrs[i] = values[i]; } } } return Holder(stores); } struct Point { int y, x; Point opBinary(string op)(Point rhs) const if (op == "+") { return Point(y + rhs.y, x + rhs.x); } } // 上 右 下 左 0 1 2 3 auto dir = [ Point(1, 0), Point(0, 1), Point(-1, 0), Point(0, -1) ]; void main() { // 入力 int W, H; readln.chomp.formattedRead("%d %d", W, H); auto M = new int[][](H); foreach (ref row; M) row = readln.split.to!(int[]); // 答えの計算 immutable INF = 10 ^^ 9; auto dist = uninitializedArray!(int[][][])(H, W, 4); fill(dist, INF); alias T = Tuple!(Point, Point, int); auto que = DList!T(T(Point(0, 1), Point(0, 0), 1), T(Point(1, 0), Point(0, 0), 2)); dist[0][0][] = 0; dist[0][1][1] = 1; dist[1][0][2] = 1; while (!que.empty) { Point p1, p2; // 1つ前、2つ前 int v; // どの方向から来たか tie(p1, p2, v) = que.front; que.removeFront; if (p1.y == H - 1 && p1.x == W - 1) break; foreach (i; 0 .. 4) { Point nxt = p1 + dir[i]; if (nxt.y < 0 || nxt.y >= H || nxt.x < 0 || nxt.x >= W) continue; if (dist[nxt.y][nxt.x][i] != INF) continue; int len0 = M[nxt.y][nxt.x]; int len1 = M[p1.y][p1.x]; int len2 = M[p2.y][p2.x]; if (len0 == len1 || len1 == len2 || len2 == len0) continue; int mid = len0 + len1 + len2 - min(len0, len1, len2) - max(len0, len1, len2); if (mid == len0 || mid == len2) { que.insertBack(T(nxt, p1, i)); dist[nxt.y][nxt.x][i] = dist[p1.y][p1.x][v] + 1; } } } // 答えの出力 int ans = dist[H - 1][W - 1].minElement; writeln(ans == INF ? -1 : ans); }