題目鏈接:https://ac.nowcoder.com/acm/contest/888/A
題目大意:給定的01矩陣,求該矩陣中極大全1矩陣的數目。
思路:
我們在處理極大全1矩陣的過程中,關鍵在於判斷當前所求矩陣是否會被包含在後續求出來的矩陣中。那麼要在知道會不會被包含在下一行的矩陣中,對於行方向:只要知道當前這一行,這個矩陣的對應的1位置,如果下一行中相應位置也全爲1,那麼一定會被包含,如果下一行中對應位置中有一個位置爲0,那麼說明這個矩陣不會被包含在下一行的最大矩陣中,當前行爲該矩陣的最後一行。對於列方向:可以先預處理一下每列的前綴和,然後對每一行用單調棧維護前綴和最大值即可。
AC代碼:
#include<bits/stdc++.h>
using namespace std;
const int maxn=3010;
int h[maxn][maxn];
int n,m;
char mp[maxn][maxn];
struct node
{
int pos;//pos存的是單調棧中對應點的列
int value;//value存的是列的前綴和(h[][])
};
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>mp[i][j];
h[i][j]=0;
}
h[i][m+1]=0;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(mp[i][j]=='1'){
h[i][j]=h[i-1][j]+1;//求每列的前綴和
}
}
}
int ans=0;
for(int i=1;i<=n;i++){
int tmpos=-1,tmp=-1;
stack<node>stk;//單調棧維護
for(int j=1;j<=m+1;j++){
tmpos=j;
while(!stk.empty()&&stk.top().value>h[i][j]){
if(stk.top().pos<=tmp){
ans++;
}
tmpos=stk.top().pos;//tmpos記錄的是單調棧中不合法的最後一個節點的位置
stk.pop();
}
if(h[i+1][j]==0){//當前列的下一行爲0,說明當前列所在的矩陣不能擴展到下一行
tmp=j;//tmp記錄當前列
}
if(h[i][j]&&(stk.empty()||stk.top().value<h[i][j])){
node t;
t.pos=tmpos,t.value=h[i][j];
stk.push(t);
}
}
}
printf("%d\n",ans);
return 0;
}