题意:
输入n和m,给出一个n行m列的01矩阵,求出所有的不可扩大的全1矩阵个数。
题解:
预处理每个格子的高度up[i][j](其向上连续的1的个数),枚举每一行 i,维护单调栈(单调上升)求每个格子 j 以up[i][j]为高可达到的全1矩阵左边界pos和右边界j,此时得到的全1矩阵不能再向上左右拓展,只要判断能否再向下拓展即可。只要下一行[pos,j]区间内有0存在,即该全1矩阵不能向下拓展。
维护单调栈时,当前点高度等于栈顶元素高度,则说明是重复的,不用计算。
Code:
手写栈:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=3005; 4 int a[maxn][maxn],sum[maxn][maxn],up[maxn][maxn],height[maxn],sta[maxn]; 5 int main() 6 { 7 int n,m; 8 scanf("%d%d",&n,&m); 9 for(int i=1;i<=n;i++){ 10 for(int j=1;j<=m;j++){ 11 scanf("%1d",&a[i][j]); 12 up[i][j]=(a[i][j]==1)?up[i-1][j]+1:0;//预处理每个格子(i,j)向上的连续的1的个数 13 sum[i][j]=sum[i][j-1]+a[i][j];//预处理每行的前缀和,方便判断矩形能否向下拓展 14 } 15 } 16 int ans=0; 17 for(int i=1;i<=n;i++){ 18 int top=0; 19 for(int j=1;j<=m+1;j++){ 20 int pos=j; 21 while(top&&up[i][j]<height[top]){ 22 if(i==n||(sum[i+1][j-1]-sum[i+1][sta[top]-1])<j-sta[top])//不可向下拓展,答案+1 23 ans++; 24 pos=sta[top];//向左最远能拓展的位置pos 25 top--; //出栈 26 } 27 if(up[i][j]&&(!top||up[i][j]>height[top])) //入栈 28 height[++top]=up[i][j],sta[top]=pos; 29 } 30 } 31 printf("%d ",ans); 32 return 0; 33 }
STL的stack:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=3005; 5 int a[maxn][maxn],up[maxn][maxn]; 6 int main() 7 { 8 int n,m; 9 scanf("%d%d",&n,&m); 10 for(int i=1;i<=n;i++){ 11 for(int j=1;j<=m;j++){ 12 scanf("%1d",&a[i][j]); 13 up[i][j]=(a[i][j]==1)?up[i-1][j]+1:0; 14 } 15 } 16 int ans=0; 17 for(int i=1;i<=n;i++){ 18 int temp=0; 19 stack<pair<int,int> >S; 20 for(int j=1;j<=m+1;j++){ 21 int pos=j; 22 while(!S.empty()&&up[i][j]<S.top().first){ 23 if(S.top().second<=temp)//下一行[pos,j]中有0存在,故不可向下扩展,答案+1 24 ans++; 25 pos=S.top().second; 26 S.pop(); 27 } 28 if(!up[i+1][j])temp=j;//记录下一行中截至当前最右边0的位置 29 if(S.empty()||up[i][j]>S.top().first) 30 S.push({up[i][j],pos}); 31 } 32 } 33 printf("%d ",ans); 34 return 0; 35 }