这几天帮同学整理题目时发现了一个挺有意思的题。
题目描述
有个n*m
规格的矩阵,每个格点由0
或1
组成,现要划出一个只由0
构成的矩形,问这个矩阵最多包含多少个节点。
输入
第一行包括两个整数n
和m
,0<n,m<=100
。
接下来为n*m
规格的只由0
和1
构成的矩阵。
输出
只由0
构成的矩形的最多格点数。
样例输入
4 5
0 1 0 1 1
0 1 0 0 1
0 0 0 0 0
0 1 1 0 1
样例输出
5
解题思路
开始的时候想枚举每一个节点,对于每一个节点维护一个矩形,对于扩展之后面积增大的就直接更新,后来算了下时间复杂度有大概O(n^4),而且实现起来也不是很容易。
后来我把侧重点放在了如何求面积,对于一个只由0
组成的区域,由于需要划矩形,矩形的面积是长×宽,所以我们对于每一块组成的矩形都可以求出其长和宽。假设我们从上到下枚举以该起点为顶点的矩形,那么在向下枚举的过程中,长是固定增加的,宽是最短那条边决定的。为了快速得到宽,我们可以用一个反向前缀和来快速得到,来表示对于每一行的0
左边连续的0
有多少个,这样处理可以把时间复杂度降到O(n^3)。分析到这里,代码也很容易写了。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 105;
int n,m;
int pic[maxn][maxn],fro[maxn][maxn];
void init()
{
memset(fro,0,sizeof fro);
scanf("%d%d",&n,&m);
for(int i=0; i<n; i++)
for(int j=0; j<m; j++)
scanf("%d",&pic[i][j]);
}
int solve()
{
for(int i=0; i<n; i++)
{
int tmp=0;
for(int j=m-1; j>=0; j--)
{
if(pic[i][j]) tmp=0;
else fro[i][j]=++tmp;
}
}
int maxx=-1;
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
if(!fro[i][j]) continue;
int row=0,col=0;
for(int k=i; k<n; k++)
{
if(fro[k][j])
{
row++;
if(col==0) col=fro[k][j];
else col=min(col,fro[k][j]);
maxx=max(maxx,row*col);
}
else break;
}
}
}
return maxx;
}
int main()
{
// freopen("in.txt","r",stdin);
init();
int ans=solve();
printf("%d\n",ans);
return 0;
}