http://www.luogu.org/problem/show?pid=1736
先O(nm)预处理r, l, up数组
分别代表在右边连续出现几个0,在左边连续出现几个0,在上边连续出现几个0
即得转移方程,f[i][j]为以i,j作为正方形的右下顶点的最大吃鱼数
主对角线:f[i][j]=min(f[i-1][j-1],left[i][j-1],up[i-1][j])+1
副对角线:f[i][j]=min(f[i-1][j+1],right[i][j+1],up[i-1][j])+1
注意搜索两条对角线要分开搜索
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ms(i,j) memset(i,j, sizeof i);
using namespace std;
int n,m;
bool map[2505][2505];
int up[2505][2505], l[2505][2505], r[2505][2505], f[2505][2505];
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]);
ms(up,0); ms(l,0); ms(r,0);
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
{
if (map[i][j]==0)
{
up[i][j] = up[i-1][j]+1;
l[i][j] = l[i][j-1]+1;
}
}
}
for (int i=n;i>0;i--)
{
for (int j=m;j>0;j--)
{
if (map[i][j]==0)
{
r[i][j] = r[i][j+1]+1;
}
}
}
ms(f,0);
int ans = 0;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
if (map[i][j])
{
f[i][j] = min(f[i-1][j-1], min(up[i-1][j], l[i][j-1]))+1;
ans = max(ans, f[i][j]);
}
}
ms(f,0);
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
if (map[i][j])
{
f[i][j] = min(f[i-1][j+1], min(up[i-1][j], r[i][j+1]))+1;
ans = max(ans, f[i][j]);
}
}
printf("%d\n", ans);
return 0;
}