题目大意
给定一个m × n(0,1)矩阵,所有元素全为1的子矩阵中哪个最大?
例如:
2 * 2
0 0
0 0
输出:
0
////////////
4 * 4
0 0 0 0
0 1 1 0
0 1 1 0
0 0 0 0
输出:
4
解题思路:
最大子矩阵一定是矩阵中某个位置先向上连续元素1延伸,然后向左右延伸得到最大面积。
因此,我们可以现预处理数据,将所有点向上延伸连续1的长度设为高,然后利用单调栈,对每一行数据进行柱形图求最大子矩阵处理,然后每一行再比较大小就可以了,关于如何求柱形图最大子矩阵,可以参考博客
https://mp.csdn.net/mdeditor/101476806#
#include <iostream>
#include <cstring>
#include <stack>
using namespace std;
int rec[2005][2005];
int h[2005][2005];
int main(){
int m,n;
while(cin>>m){
int maxArea=0;
cin>>n;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
cin>>rec[i][j];
//预处理矩阵数据,统计每一个位置向上延续的最大高度
memset(h,0,sizeof(h));
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++){
if(rec[i][j]==0)
h[i][j]=0;
else
h[i][j]=h[i-1][j]+1;
}
//对每一行数据求柱形图最大子矩阵
for(int i=1;i<=m;i++){
stack <int> st;
int height=0,wide=0;
for(int j=1;j<=n+1;j++){
if(st.empty()||h[i][st.top()]<h[i][j])
st.push(j);
else{
while(!st.empty()&&h[i][j]<=h[i][st.top()])
{
height=h[i][st.top()];
st.pop();
wide=st.empty() ? (j-1) : j-(st.top()+1) ;
maxArea=max(maxArea,height*wide);
}
st.push(j);
}
}
}
cout<<maxArea<<endl;
}
return 0;
}
求柱形图最大子矩阵含注释代码:
#include <iostream>
#include <stack>
#include <cstring>
#include <stdio.h>
using namespace std;
int height[100005];
int main(){
int n;
scanf("%d",&n);
while(n!=0){
memset(height,0,n+10);//初始化height数组
stack <int> st;//定义一个st栈,用于存放每个矩阵长度单调递增下标索引
long long h,w;
long long maxArea=0;
int x,j;
for(j=0;j<n;j++)
scanf("%d",&height[j]);
height[j]=0;//加高度为0的矩形条用于收割
for(int i=0;i<=n;i++){
if(st.empty()||height[st.top()]<height[i])//无法确定栈顶矩阵右边界,继续压栈
st.push(i);
else{
while(!st.empty()&&height[i]<=height[st.top()])//确定当前栈顶元素右边界,出栈算面积
{
h=height[st.top()];
st.pop();
w=st.empty() ? i : i-(st.top()+1) ;//栈为空返回长度i,非空返回长度为当前下标减去栈顶矩阵的位置+1;
maxArea=max(maxArea,h*w);//比较每一个子矩阵的面积,选出最大的
}
st.push(i);//当前矩阵条进栈
}
}
printf("%lld\n",maxArea);
scanf("%d",&n);
}
return 0;
}
参考博客:
https://blog.csdn.net/qq_42936517/article/details/89501802