最大全1子矩阵(多解)
作者:互联网
这是很经典的一个问题了
题目很多就随便找了一个https://vjudge.net/problem/POJ-3494
n^3 解法
预处理二维矩阵前缀和
n^2解法:
设h[j]为从当前行开始向上数连续的0的个数(包含当前行)
比如说这个
5 对应的h[j]
10101 10101
11111 21212
11010 32020
01111 03131
10111 10242
然后找当前位置向左和向右有多少连续的1,存在l[j] 和 r[j] 中
初始值为j,显然如果h[j] <= h[l[j] - 1] (用图形来说就是j左边的矩形向上扩展的大,那么左边的矩阵就可以并入当前位置)
那么l[j] = l[l[j] - 1]
同理可得:如果h[j]<=h[r[j]+1],那么r[j]=r[r[j]+1];
然后答案就是h[j]*(r[j]-l[j]+1)
ps:可能有人觉得上面讲的数组啥的和i没有关系,这就是将h的二维变一维,因为行数是在不断枚举的,这一行的状态只与上一行有关,所以可以省去。
#include<iostream>
#include<cstdio>
using namespace std;
int n,m,ans;
int a[2010][2010],h[2010],r[2010],l[2010];
int main()
{
while(~scanf("%d%d",&n,&m))
{
ans = 0;
for(int i = 1;i <= n; ++i)
for(int j = 1;j <= m; ++j)
scanf("%d",&a[i][j]);
for(int i = 1;i <= m; ++i) h[i] = 0;
for(int i = 1;i <= n; ++i)
{
for(int j = 1;j <= m; ++j)
if(a[i][j]) h[j]++;
else h[j] = 0; //更新h[j]
for(int j = 1;j <= m; ++j)
{
l[j] = j;
while(l[j] > 1 && h[j] <= h[l[j] - 1])
l[j] = l[l[j] - 1];
}
for(int j = n; j >= 1; --j)
{
r[j] = j;
while(r[j] < m && h[j] <= h[r[j] + 1])
r[j] = r[r[j] + 1];
}
for(int j = 1;j <= n; ++j)
ans = max(ans,(r[j] - l[j] + 1) * h[j]);
}
printf("%d\n",ans);
}
return 0;
}
注意:r数组算的时候,因为是根据右边的算左边的,所以应该从n往前算
单调栈解法:
读入矩阵,预处理出a数组
a[i][j] 表示在第i行,第j个元素前面(包括自身)的连续的1的个数
对于点(i,j),在这一列向上和向下查找比a[i][j]小的值,其行数记为y1,y2,那么就可以得到一个包含(i,j)的全1子矩阵
面积为 (y2 - y1 -1)*a[i][j]
所以写了个朴素的方法TLE了hhh
#include<iostream>
#include<cstdio>
using namespace std;
int n,m,ans;
int a[2010][2010],x[2010][2010];
int main()
{
while(~scanf("%d%d",&n,&m))
{
ans = 0;
for(int i = 1;i <= n; ++i)
for(int j = 1;j <= m; ++j)
{
scanf("%d",&x[i][j]);
if(x[i][j]) a[i][j] = a[i][j - 1] + 1;
else a[i][j] = 0;
}
for(int i = 1;i <= n; ++i)
{
for(int j = 1;j <= m; ++j)
{
int k = i - 1;
while(k >= 1 && a[k][j] >= a[i][j]) k--;
int k1 = i + 1;
while(k1 <= n && a[k1][j] >= a[i][j]) k1++;
//cout<<i<<' '<<j<<' '<<k<<' '<<k1<<endl;
ans = max(ans,(k1 - k - 1) * a[i][j]);
}
}
printf("%d\n",ans);
}
return 0;
}
所以就说到单调栈来优化了
标签:最大,int,矩阵,多解,while,ans,include,2010 来源: https://blog.csdn.net/qq_29904713/article/details/96628390