【题解】
起先搜索将整张图遍历一遍,求出每个第一行的格子能覆盖到的最后一行的最左和最右的格子用g[1][j][0/1]表示(刚开始用广搜(注释的部分),每次求一个格子都遍历一边(比较蠢)复杂度是o(n*m^2)只能过七十分,后来改成了深搜只遍历一遍算出所有,复杂度o(n*m))
算出了上述的东西后,就是一个经典的区间覆盖动归(用第一行覆盖最后一行)
f[i]表示最后一行前i的格子都已经被覆盖时所需要的第一行格子的最小值
f[i]=min(f[i],f[g[1][j][0]-1]+1)详见代码
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cstdio>
#include <queue>
#include <ctime>
#include <cmath>
#include <vector>
using namespace std;
int i,j,k,l,m,n;
int f[505],flag[505][505],q[50000][2],g[505][505][2],h,t,a[505][505],xx[4]={-1,0,1,0},yy[4]={0,1,0,-1};
void dfs(int x,int y)
{
int x2,y2;
flag[x][y]=1;
if (x==n) g[x][y][0]=g[x][y][1]=y;
for (int i=0;i<4;i++)
{
x2=x+xx[i];
y2=y+yy[i];
if (a[x][y]>a[x2][y2])
{
if (!flag[x2][y2]) dfs(x2,y2);
g[x][y][0]=min(g[x][y][0],g[x2][y2][0]);
g[x][y][1]=max(g[x][y][1],g[x2][y2][1]);
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++) for (j=1;j<=m;j++) scanf("%d",&a[i][j]);
for (i=0;i<=m;i++) a[0][i]=a[n+1][i]=1e9;
for (i=0;i<=n;i++) a[i][0]=a[i][m+1]=1e9;
for (i=1;i<=n;i++) for (j=1;j<=m;j++) g[i][j][0]=m+1,g[i][j][1]=0;
/*for (i=1;i<=m;i++)
{
t++;q[t][0]=1;q[t][1]=i;flag[1][i]=1;
}
for (;h<t;)
{
h++;
// if (q[h][0]==n) g[i][0]=min(g[i][0],q[h][1]);g[i][1]=max(g[i][1],q[h][1]);
for (j=0;j<4;j++)
if (a[q[h][0]+x[j]][q[h][1]+y[j]]<a[q[h][0]][q[h][1]]&&flag[q[h][0]+x[j]][q[h][1]+y[j]]==0)
{
flag[q[h][0]+x[j]][q[h][1]+y[j]]=i;
t++;q[t][0]=q[h][0]+x[j];q[t][1]=q[h][1]+y[j];
g[q[h][0]][q[h][1]][0]=min(g[q[h][0]][q[h][1]][0]
}
}*/
for (i=1;i<=m;i++) dfs(1,i);
l=0;
for (i=1;i<=m;i++)
if (flag[n][i]==0) l++;
if (l>0) {printf("0\n%d",l);return 0;}
for (i=1;i<=m;i++)
{
f[i]=1e9;
for (j=1;j<=m;j++)
if (i>=g[1][j][0]&&i<=g[1][j][1])
f[i]=min(f[i],f[g[1][j][0]-1]+1);
}
printf("1\n%d",f[m]);
}