#include<cstdio>
#include<queue>
#include<cstring>
#include<iostream>
using
namespace
std;
struct
T
{
int
x,y;
T(){}
T(
int
a,
int
b)
{
x = a,y = b;
}
};
queue<T> myque;
int
map[505][505];
bool
p[505][505];
int
n,m;
int
dd[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
void
bfs()
{
for
(
int
i = 1; i <= m; i++)
//推断可以到达的全部顶点
{
p[1][i] = 1;
myque.push(T(1,i));
}
while
(!myque.empty())
{
T u = myque.front();
myque.pop();
for
(
int
i = 0; i < 4; i++)
{
int
xx = u.x + dd[i][0];
int
yy = u.y + dd[i][1];
if
(xx>n||xx<1||yy>m||yy<1)
continue
;
if
(p[xx][yy])
continue
;
if
(map[u.x][u.y] <= map[xx][yy])
continue
;
p[xx][yy] = 1;
myque.push(T(xx,yy));
}
}
}
int
cur;
int
g[505][2],f[505];
void
dfs(
int
x,
int
y)
//找到每条线段的左右端点
{
p[x][y] = 1;
if
(x == n)
{
g[cur][0] = min(g[cur][0],y);
g[cur][1] = max(g[cur][1],y);
}
for
(
int
i = 0; i < 4; i++)
{
int
xx = x + dd[i][0];
int
yy = y + dd[i][1];
if
(xx>n||xx<1||yy>m||yy<1)
continue
;
if
(map[x][y] <= map[xx][yy])
continue
;
if
(!p[xx][yy])
dfs(xx,yy);
}
}
int
main()
{
scanf
(
"%d%d"
,&n,&m);
for
(
int
i = 1; i <= n; i++)
for
(
int
j = 1; j <= m; j++)
scanf
(
"%d"
,&map[i][j]);
bfs();
//推断是否有解
int
rest = 0;
//没有被覆盖的点
for
(
int
i = 1; i <= m; i++)
if
(!p[n][i]) rest++;
if
(rest)
{
printf
(
"0\n"
);
printf
(
"%d\n"
,rest);
return
0;
}
printf
(
"1\n"
);
for
(
int
i = 1; i <= m; i++)
{
memset
(p,0,
sizeof
p);
cur = i;
g[cur][0] = m+1;
g[cur][1] = 0;
dfs(1,cur);
}
for
(
int
i = 1; i <= m; i++)
//dp,最小线段覆盖问题
{
f[i] = 123546;
for
(
int
j = 1; j <= m; j++)
if
(i >= g[j][0]&&i <= g[j][1])
f[i] = min(f[i],f[g[j][0]-1]+1);
}
printf
(
"%d\n"
,f[m]);
}