题目背景
感谢@throusea 贡献的两组数据
题目描述
回到家中的猫猫把三桶鱼全部转移到了她那长方形大池子中,然后开始思考:到底要以何种方法吃鱼呢(猫猫就是这么可爱,吃鱼也要想好吃法 ^_*)。她发现,把大池子视为01矩阵(0表示对应位置无鱼,1表示对应位置有鱼)有助于决定吃鱼策略。
在代表池子的01矩阵中,有很多的正方形子矩阵,如果某个正方形子矩阵的某条对角线上都有鱼,且此正方形子矩阵的其他地方无鱼,猫猫就可以从这个正方形子矩阵“对角线的一端”下口,只一吸,就能把对角线上的那一队鲜鱼吸入口中。
猫猫是个贪婪的家伙,所以她想一口吃掉尽量多的鱼。请你帮猫猫计算一下,她一口下去,最多可以吃掉多少条鱼?
输入格式
有多组输入数据,每组数据:
第一行有两个整数n和m(n,m≥1),描述池塘规模。接下来的n行,每行有m个数字(非“0”即“1”)。每两个数字之间用空格隔开。
对于30%的数据,有n,m≤100
对于60%的数据,有n,m≤1000
对于100%的数据,有n,m≤2500
输出格式
只有一个整数——猫猫一口下去可以吃掉的鱼的数量,占一行,行末有回车。
输入输出样例
输入 #1复制
4 6 0 1 0 1 0 0 0 0 1 0 1 0 1 1 0 0 0 1 0 1 1 0 1 0
输出 #1复制
3
说明/提示
右上角的
1 0 0
0 1 0
0 0 1
思路
拿到这题立马想到了最大正方形那题,可是却不会推方程。写了个记忆化搜索。
怎么去搜?对于任意一个子正方形,要满足鱼都在对角线,也就是对角线的数字不为0;子正方形其他地方没有鱼,也就是对角线以外都是0。假如(x,y)有鱼,那就可以dfs(x+1,y+1)和dfs(x+1,y-1)来判断对角线上是否有鱼。既然一个子正方形只有对角线有鱼,那么该正方形的数字和就是对角线的长度。所以利用二维前缀和把整个矩形总和算出来。
#include <stdio.h>
#include <iostream>
#define N 2501
using namespace std;
int a[N][N],dp[N][N][2],sum[N][N],n,m,s,orgx,orgy;
int tox[5]={0,1,0,-1,0},toy[5]={0,0,1,0,-1};
int dfs1(int x,int y)
{
if(x>n || y>m ) return 0;
//if(dp[x][y][0]) return dp[x][y][0];//为什么注释?下面有解释
register int cnt(sum[x][y]-sum[orgx-1][y]-sum[x][orgy-1]+sum[orgx-1][orgy-1]);
if(cnt!=x-orgx+1 || a[x][y]==0)
{
return 0;
}
dp[x][y][0]=dfs1(x+1,y+1)+1;
if(dp[x][y][0]) return dp[x][y][0];//为什么到这里才进行记忆化?下面有解释
}
int dfs2(int x,int y)
{
if(x>n || y<1 ) return 0;
register int cnt(sum[x][orgy]-sum[orgx-1][orgy]-sum[x][y-1]+sum[orgx-1][y-1]);
if(cnt!=x-orgx+1 || a[x][y]==0)
{
return 0;
}
dp[x][y][1]=dfs2(x+1,y-1)+1;
if(dp[x][y][1]) return dp[x][y][1];
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
register int i,j,k;
cin>>n>>m;
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
cin>>a[i][j];
sum[i][j]=sum[i][j]+sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+a[i][j];
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
orgx=i;
orgy=j;
dp[i][j][0]=dfs1(i,j);
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
orgx=i;
orgy=j;
dp[i][j][1]=dfs2(i,j);
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
s=max(s,max(dp[i][j][0],dp[i][j][1]));
}
}
cout<<s<<endl;
return 0;
}
接下来来解答代码注释中的问题。
假设有如下4*4的矩形:
1 0 1 0
0 1 0 0
1 0 1 0
0 0 0 1
答案是3,但如果把注释那句话放到前面,答案会就变成2。因为dp[2][2][0]会先复制成2,再次枚举到该点时会直接返回,而得不到右下角的正确矩形。